I've got a string that I'm trying to split into chunks based on blank lines.
Given a string s
, I thought I could do this:
re.split('(?m)^\s*$', s)
This works in some cases:
>>> s = 'foo\nbar\n \nbaz'
>>> re.split('(?m)^\s*$', s)
['foo\nbar\n', '\nbaz']
But it doesn't work if the line is completely empty:
>>> s = 'foo\nbar\n\nbaz'
>>> re.split('(?m)^\s*$', s)
['foo\nbar\n\nbaz']
What am I doing wrong?
[python 2.5; no difference if I compile '^\s*$'
with re.MULTILINE
and use the compiled expression instead]
The most portable regex would be ^[ \t\n]*$ to match an empty string (note that you would need to replace \t and \n with tab and newline accordingly) and [^ \n\t] to match a non-whitespace string. Save this answer.
An empty regular expression matches everything.
To match a character having special meaning in regex, you need to use a escape sequence prefix with a backslash ( \ ). E.g., \. matches "." ; regex \+ matches "+" ; and regex \( matches "(" . You also need to use regex \\ to match "\" (back-slash).
$ means "Match the end of the string" (the position after the last character in the string). Both are called anchors and ensure that the entire string is matched instead of just a substring.
Try this instead:
re.split('\n\s*\n', s)
The problem is that "$ *^" actually only matches "spaces (if any) that are alone on a line"--not the newlines themselves. This leaves the delimiter empty when there's nothing on the line, which doesn't make sense.
This version also gets rid of the delimiting newlines themselves, which is probably what you want. Otherwise, you'll have the newlines stuck to the beginning and end of each split part.
Treating multiple consecutive blank lines as defining an empty block ("abc\n\n\ndef" -> ["abc", "", "def"]) is trickier...
The re library can split on one or more empty lines ! An empty line is a string that consists of zero or more whitespaces, starts at the start of the line and ends at the end of a line. Special character '$' matches the end of the string or just before the newline at the end of the string, and in MULTILINE mode also matches before a newline (excerpt from docs). That's why we need to add a special character '\s*' for the line break. Everything is possible :-)
>>> import re
>>> text = "foo\n \n \n \nbar\n"
>>> re.split("(?m)^\s*$\s*", text)
['foo\n', 'bar\n']
The same regex works with windows style line breaks.
>>> import re
>>> text = "foo\r\n \r\n \r\n \r\nbar\r\n"
>>> re.split("(?m)^\s*$\s*", text)
['foo\r\n', 'bar\r\n']
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With