Backport Python 3.4's regular expression "fullmatch()" to Python 2
Asked Answered
E

2

11

Python 3.4 introduced the new regex method re.fullmatch(pattern, string, flags=0).

Has anyone back-ported this new method to older Python versions?

Enunciation answered 13/5, 2015 at 10:39 Comment(0)
H
22

To make sure that the entire string matches, you need to use the \Z end-of-string anchor:

def fullmatch(regex, string, flags=0):
    """Emulate python-3.4 re.fullmatch()."""
    return re.match("(?:" + regex + r")\Z", string, flags=flags)

The \A anchor is not necessary since re.match() already anchors the match to the start of the string.

Hierogram answered 13/5, 2015 at 10:56 Comment(3)
Can also use $ to match until end-of-line.Arlo
@gaborous: That might backfire since regex could contain a (?m) modifier, and then less than the entire string could match.Hierogram
Does the r")\Z" part need to be a raw string literal, or maybe this is just a habit of yours? Neither Python 2 nor 3 treat \Z in any special way, so I think this is not mandatory, but who knows...Agro
E
2

Here it is my backporting, which has at least one problem (thanks tim-pietzcker) but does not require recompiling regexes:

import re

def fullmatch(regex, string, flags=0):
    """Emulate python-3.4 re.fullmatch()."""
    m = re.match(regex, string, flags=flags)
    if m and m.span()[1] == len(string):
        return m

And here are some test-cases proving the above emulation-function.

def compare_expansion(regex, s, template):
    m1 = re.fullmatch(regex, s)
    s1 = m1.expand(template) if m1 else '<NO-MATCH>'
    m2 = fullmatch(regex, s)
    s2 = m2.expand(template) if m2 else '<NO-MATCH>'
    if s1 != s2:
        raise AssertionError("\n  PY-3: '%s' \n  PY-2: '%s' " % (s1, s2))

compare_expansion('.*', 'foo', r'A')
compare_expansion('(.*)', 'foo', r'A_\1')
compare_expansion('(.*)', 'foo', r'A_\g<0>')

compare_expansion('a.*', 'afoo&', r'A')
compare_expansion('a(\w*)', 'afoo&', r'A_\1')
compare_expansion('a(\w*)', 'afoo&', r'A_\g<0>')

## But this fails!
compare_expansion(".*?", "Hello", '\g<0>')
AssertionError: 
  PY-3: 'A_Hello' 
  PY-2: '<NO-MATCH>' 
Enunciation answered 13/5, 2015 at 10:39 Comment(2)
This fails with lazy quantifiers: re.fullmatch(".*?", "Hello") returns None where it should return a match.Hierogram
I also tried this approach years ago, and it is not correct. You don't need things like *? for this, it suffices to have a regex a|ab. For the input "ab" the match would be just of a, causing the fullmatch approach here to claim that the regex does not match the whole input string.Dufrene

© 2022 - 2024 — McMap. All rights reserved.