tags:

views:

83

answers:

5

I'm expecting a string NOT to match a regular expression, but it is!

>>> re.compile('^P|([LA]E?)$').match('PE').group()
'P'

This seems like a bug, because I see no way for the $ to match. On the other hand, it seems unlikely that Python's re lib would not be able to handle this simple case. Am I missing something here?

btw, Python prints this out when I start it:

Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information.

+3  A: 

You wrote "P or ([LA]E?)". "P" matches.

If you meant for the anchors to apply to both cases, then perhaps you meant this:

^(?:P|([LA]E?))$

Shirik
`^P$|^([LA]E?)$` also works.
icktoofay
+1  A: 

It will match either ^P or ([LA]E)$. Did you mean ^(?:P|([LA]E?))$ instead?

Ignacio Vazquez-Abrams
+4  A: 
^P|([LA]E?)$

becomes

^P
|
([LA]E?)$
Amber
Ah, yes. I'm guessing it parses this way, because ^ and $ are treated like regular characters. Is that right?
allyourcode
They're treated like anything else in an expression aside from the `|` character, which has a very low grouping priority.
Amber
A: 

It prints the same output on Mac OS X and on Linux(Debian testing). I would be surprised to see a bug behave the same on three major platforms. Besides, 'PE' has 'P' in the beginning, so I don't see a problem in it matching the regex. Similarly, 'AE' matches the regex too. On both Debian and on Mac OS X.

vpit3833
It's not a bug, it's that the regex as written is not what the asker intended.
Ignacio Vazquez-Abrams
+2  A: 

Two other points worth mentioning: ^ is redundant when you use re.match(), and if you want to match the end of the string, use r"\Z", not "$".

Why $ is evil: Suppose we want to check that the whole of some string s matches some pattern foo. We don't want to call it a match if there is anything after the pattern. Let's see what happens if there is a newline after the pattern.

>>> import re
>>> s = 'foo\n'
>>> re.match('foo$', s)
<_sre.SRE_Match object at 0x00BAFE90> # match -- FAIL!
>>> re.match('foo\Z', s) # no match -- OK
>>>

Here are excerpts from the docs:

Docs for $: Matches the end of the string or just before the newline at the end of the string ... this is using the default modes, and is nothing to do with MULTILINE mode.

Docs for \Z: Matches only at the end of the string. Nothing to do with modes, and not spooked by newlines.

John Machin
What is \Z? I'm pretty sure $ matches the end of the string (unless you're using re.MULTILINE)
allyourcode
@allyourcode: see my updated answer
John Machin
OOh! Thanks! Yes, $ seems very evil now that I know this. On the other hand, I believe most people know $, making it more readable than \Z :/
allyourcode
readability comes after correctness!
John Machin