You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've noticed a subtle bug in some of our internal code. Someone wants to ensure that a certain string (e.g. a URL path) matches a certain pattern in its entirety. They use re.match() with a regex ending in $. Fine. Now someone else comes along and modifies the pattern. Somehow the $ gets lost, or the pattern develops a set of toplevel choices that don't all end in $. And now things that have a valid *prefix* suddenly (and unintentionally) start matching.
I think this is a common enough issue and propose a new API: a fullmatch() function and method that work just like the existing match() function and method but also check that the whole input string matches. This can be implemented slightly awkwardly as follows in user code:
+1. Note that this really can't be done in user-level code. For example, consider matching the pattern
a|ab
against the string
ab
Without being _forced_ to consider the "ab" branch, the regexp will match just the "a" branch. So, e.g., the example code you posted will say "nope, it didn't match (the whole thing)".
Antoine, that's certainly the conceptual intent here. Can't say whether your attempt works in all cases. The docs don't guarantee it. For example, if the original regexp started with (?x), the docs explicitly say the effect of (?x) is undefined "if there are non-whitespace characters before the [inline (?x)] flag".
Sure, you could parse the regexp is user code too, and move an initial (?...x...) before your non-capturing group. For that matter, you could write your own regexp engine in user code too ;-)
The point is that it should be easy for the regexp engine to implement the desired functionality - and user attempts to "fake it" have pitfalls (even Guido didn't get it right - LOL ;-) ).
mrabarnett commented on Oct 12, 2012
mrabarnettmannequin
Mannequin
More actions
'$' will match at the end of the string or just before the final '\n':
>>> re.match(r'abc$', 'abc\n')
<_sre.SRE_Match object at 0x00F15448>
Matthew, Guido wrote "check that the whole input string matches" (or slice if pos and (possibly also) endpos is/are given). So, yes, \Z is more to the point than $ if people want to continue wasting time trying to implement this as a Python-level function ;-)
I don't understand what you're asking about MULTILINE. What's the issue there? Focus on Guido's "whole input string matches", not on his motivational talk about "a regex ending in $". $ and/or \Z aren't the point here; "whole input string matches" is the point.
mrabarnett commented on Oct 13, 2012
mrabarnettmannequin
Mannequin
More actions
Tim, my point is that if the MULTILINE flag happens to be turned on, '$' won't just match at the end of the string (or slice), it'll also match at a newline, so wrapping the pattern in (?:...)$ in that case could give the wrong answer, but wrapping it in (?:...)\Z would give the right answer.
Tim, my point is that if the MULTILINE flag happens to be turned on,
'$' won't just match at the end of the string (or slice), it'll also
match at a newline, so wrapping the pattern in (?:...)$ in that case
could give the wrong answer, but wrapping it in (?:...)\Z would give
the right answer.
This means Tim and Guido are right that a dedicated fullmatch() method
is desireable.
Serhiy, I expect this is easy to implement _inside_ the regexp engine. The complications come from trying to do it outside the engine. But even there, wrapping the original regexp <re> in
(?:<re>)\Z
is at worst very close. The only insecurity with that I've thought of concerns the doc's warnings about what can appear before an inline re.VERBOSE flag. It probably works fine even if <re> does begin with (?...x....).
mrabarnett commented on Oct 14, 2012
mrabarnettmannequin
Mannequin
More actions
It certainly appears to ignore the whitespace, even if the "(?x)" is at the end of the pattern or in the middle of a group.
Another point we need to consider is that the user might want to use a pre-compiled pattern.
mrabarnett commented on Oct 16, 2012
mrabarnettmannequin
Mannequin
More actions
I'm about to add this to my regex implementation and, naturally, I want it to have the same name for compatibility.
However, I'm not that keen on "fullmatch" and would prefer "matchall" instead.
I updated the patch to current tip, fixed three issues from the review, and added documentation updates.
python-dev commented on Oct 13, 2013
python-devmannequin
Mannequin
More actions
New changeset b51218966201 by Georg Brandl in branch 'default':
Add re.fullmatch() function and regex.fullmatch() method, which anchor the http://hg.python.org/cpython/rev/b51218966201
Activity
gvanrossum commentedon Oct 11, 2012
I've noticed a subtle bug in some of our internal code. Someone wants to ensure that a certain string (e.g. a URL path) matches a certain pattern in its entirety. They use re.match() with a regex ending in $. Fine. Now someone else comes along and modifies the pattern. Somehow the $ gets lost, or the pattern develops a set of toplevel choices that don't all end in $. And now things that have a valid *prefix* suddenly (and unintentionally) start matching.
I think this is a common enough issue and propose a new API: a fullmatch() function and method that work just like the existing match() function and method but also check that the whole input string matches. This can be implemented slightly awkwardly as follows in user code:
(The corresponding method will have to be somewhat more complex because the underlying match() method takes optional pos and endpos arguments.)
tim-one commentedon Oct 11, 2012
+1. Note that this really can't be done in user-level code. For example, consider matching the pattern
a|ab
against the string
ab
Without being _forced_ to consider the "ab" branch, the regexp will match just the "a" branch. So, e.g., the example code you posted will say "nope, it didn't match (the whole thing)".
serhiy-storchaka commentedon Oct 11, 2012
What will be with non-greedy qualifiers? Should '.*?' full match any string?
pitrou commentedon Oct 11, 2012
Well, how about:
tim-one commentedon Oct 11, 2012
Antoine, that's certainly the conceptual intent here. Can't say whether your attempt works in all cases. The docs don't guarantee it. For example, if the original regexp started with (?x), the docs explicitly say the effect of (?x) is undefined "if there are non-whitespace characters before the [inline (?x)] flag".
Sure, you could parse the regexp is user code too, and move an initial (?...x...) before your non-capturing group. For that matter, you could write your own regexp engine in user code too ;-)
The point is that it should be easy for the regexp engine to implement the desired functionality - and user attempts to "fake it" have pitfalls (even Guido didn't get it right - LOL ;-) ).
mrabarnett commentedon Oct 12, 2012
'$' will match at the end of the string or just before the final '\n':
So shouldn't you be using r'\Z' instead?
And what happens if the MULTILINE flag is turned on?
tim-one commentedon Oct 13, 2012
Matthew, Guido wrote "check that the whole input string matches" (or slice if pos and (possibly also) endpos is/are given). So, yes, \Z is more to the point than $ if people want to continue wasting time trying to implement this as a Python-level function ;-)
I don't understand what you're asking about MULTILINE. What's the issue there? Focus on Guido's "whole input string matches", not on his motivational talk about "a regex ending in $". $ and/or \Z aren't the point here; "whole input string matches" is the point.
mrabarnett commentedon Oct 13, 2012
Tim, my point is that if the MULTILINE flag happens to be turned on, '$' won't just match at the end of the string (or slice), it'll also match at a newline, so wrapping the pattern in (?:...)$ in that case could give the wrong answer, but wrapping it in (?:...)\Z would give the right answer.
pitrou commentedon Oct 13, 2012
This means Tim and Guido are right that a dedicated fullmatch() method
is desireable.
serhiy-storchaka commentedon Oct 13, 2012
Definitely this is not easy issue.
tim-one commentedon Oct 14, 2012
Serhiy, I expect this is easy to implement _inside_ the regexp engine. The complications come from trying to do it outside the engine. But even there, wrapping the original regexp <re> in
(?:<re>)\Z
is at worst very close. The only insecurity with that I've thought of concerns the doc's warnings about what can appear before an inline re.VERBOSE flag. It probably works fine even if <re> does begin with (?...x....).
mrabarnett commentedon Oct 14, 2012
It certainly appears to ignore the whitespace, even if the "(?x)" is at the end of the pattern or in the middle of a group.
Another point we need to consider is that the user might want to use a pre-compiled pattern.
mrabarnett commentedon Oct 16, 2012
I'm about to add this to my regex implementation and, naturally, I want it to have the same name for compatibility.
However, I'm not that keen on "fullmatch" and would prefer "matchall" instead.
What do you think?
15 remaining items
pitrou commentedon Oct 12, 2013
Serhiy, sorry to ping you, but do you think you're gonna look at this?
birkenfeld commentedon Oct 13, 2013
I updated the patch to current tip, fixed three issues from the review, and added documentation updates.
python-dev commentedon Oct 13, 2013
New changeset b51218966201 by Georg Brandl in branch 'default':
Add re.fullmatch() function and regex.fullmatch() method, which anchor the
http://hg.python.org/cpython/rev/b51218966201
birkenfeld commentedon Oct 13, 2013
Sorry, accidental push, already reverted.
serhiy-storchaka commentedon Oct 26, 2013
Patch updated to current tip. I have added some changes from the review and have added some tests.
Matthew, why change for SRE_OP_REPEAT_ONE is needed? Tests are passed without it.
serhiy-storchaka commentedon Nov 16, 2013
Matthew, could you please answer my question?
mrabarnett commentedon Nov 16, 2013
I don't know that it's not needed.
python-dev commentedon Nov 23, 2013
New changeset 89dfa2671c83 by Serhiy Storchaka in branch 'default':
Issue bpo-16203: Add re.fullmatch() function and regex.fullmatch() method,
http://hg.python.org/cpython/rev/89dfa2671c83
serhiy-storchaka commentedon Nov 23, 2013
Committed with additional test (re.fullmatch('a+', 'ab')) which proves that change for SRE_OP_REPEAT_ONE are needed.
Thank you Matthew for your contribution.