Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching blank lines with regular expressions

Tags:

python

regex

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]

like image 844
John Fouhy Avatar asked Jul 29 '09 01:07

John Fouhy


People also ask

How do you match a blank line in regex?

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.

Does empty regex match everything?

An empty regular expression matches everything.

How do you match a regular expression?

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).

What does '$' mean in regex?

$ 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.


2 Answers

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...

like image 176
Glenn Maynard Avatar answered Sep 28 '22 18:09

Glenn Maynard


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']
like image 42
Sascha Gottfried Avatar answered Sep 28 '22 16:09

Sascha Gottfried