Commit 77b36573 authored by Georg Brandl's avatar Georg Brandl

Add re.fullmatch() function and regex.fullmatch() method, which anchor the

pattern at both ends of the string to match.

Patch by Matthew Barnett.
Closes #16203.
parent a440d2b9
...@@ -584,6 +584,16 @@ form. ...@@ -584,6 +584,16 @@ form.
instead (see also :ref:`search-vs-match`). instead (see also :ref:`search-vs-match`).
.. function:: fullmatch(pattern, string, flags=0)
If the whole *string* matches the regular expression *pattern*, return a
corresponding :ref:`match object <match-objects>`. Return ``None`` if the
string does not match the pattern; note that this is different from a
zero-length match.
.. versionadded:: 3.4
.. function:: split(pattern, string, maxsplit=0, flags=0) .. function:: split(pattern, string, maxsplit=0, flags=0)
Split *string* by the occurrences of *pattern*. If capturing parentheses are Split *string* by the occurrences of *pattern*. If capturing parentheses are
...@@ -778,6 +788,24 @@ attributes: ...@@ -778,6 +788,24 @@ attributes:
:meth:`~regex.search` instead (see also :ref:`search-vs-match`). :meth:`~regex.search` instead (see also :ref:`search-vs-match`).
.. method:: regex.fullmatch(string[, pos[, endpos]])
If the whole *string* matches this regular expression, return a corresponding
:ref:`match object <match-objects>`. Return ``None`` if the string does not
match the pattern; note that this is different from a zero-length match.
The optional *pos* and *endpos* parameters have the same meaning as for the
:meth:`~regex.search` method.
>>> pattern = re.compile("o[gh]")
>>> pattern.fullmatch("dog") # No match as "o" is not at the start of "dog".
>>> pattern.fullmatch("ogre") # No match as not the full string matches.
>>> pattern.fullmatch("doggie", 1, 3) # Matches within given limits.
<_sre.SRE_Match object at ...>
.. versionadded:: 3.4
.. method:: regex.split(string, maxsplit=0) .. method:: regex.split(string, maxsplit=0)
Identical to the :func:`split` function, using the compiled pattern. Identical to the :func:`split` function, using the compiled pattern.
......
...@@ -85,16 +85,17 @@ resulting RE will match the second character. ...@@ -85,16 +85,17 @@ resulting RE will match the second character.
\\ Matches a literal backslash. \\ Matches a literal backslash.
This module exports the following functions: This module exports the following functions:
match Match a regular expression pattern to the beginning of a string. match Match a regular expression pattern to the beginning of a string.
search Search a string for the presence of a pattern. fullmatch Match a regular expression pattern to all of a string.
sub Substitute occurrences of a pattern found in a string. search Search a string for the presence of a pattern.
subn Same as sub, but also return the number of substitutions made. sub Substitute occurrences of a pattern found in a string.
split Split a string by the occurrences of a pattern. subn Same as sub, but also return the number of substitutions made.
findall Find all occurrences of a pattern in a string. split Split a string by the occurrences of a pattern.
finditer Return an iterator yielding a match object for each match. findall Find all occurrences of a pattern in a string.
compile Compile a pattern into a RegexObject. finditer Return an iterator yielding a match object for each match.
purge Clear the regular expression cache. compile Compile a pattern into a RegexObject.
escape Backslash all non-alphanumerics in a string. purge Clear the regular expression cache.
escape Backslash all non-alphanumerics in a string.
Some of the functions in this module takes flags as optional parameters: Some of the functions in this module takes flags as optional parameters:
A ASCII For string patterns, make \w, \W, \b, \B, \d, \D A ASCII For string patterns, make \w, \W, \b, \B, \d, \D
...@@ -123,7 +124,7 @@ import sre_compile ...@@ -123,7 +124,7 @@ import sre_compile
import sre_parse import sre_parse
# public symbols # public symbols
__all__ = [ "match", "search", "sub", "subn", "split", "findall", __all__ = [ "match", "fullmatch", "search", "sub", "subn", "split", "findall",
"compile", "purge", "template", "escape", "A", "I", "L", "M", "S", "X", "compile", "purge", "template", "escape", "A", "I", "L", "M", "S", "X",
"U", "ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE", "U", "ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE",
"UNICODE", "error" ] "UNICODE", "error" ]
...@@ -154,6 +155,11 @@ def match(pattern, string, flags=0): ...@@ -154,6 +155,11 @@ def match(pattern, string, flags=0):
a match object, or None if no match was found.""" a match object, or None if no match was found."""
return _compile(pattern, flags).match(string) return _compile(pattern, flags).match(string)
def fullmatch(pattern, string, flags=0):
"""Try to apply the pattern to all of the string, returning
a match object, or None if no match was found."""
return _compile(pattern, flags).fullmatch(string)
def search(pattern, string, flags=0): def search(pattern, string, flags=0):
"""Scan through string looking for a match to the pattern, returning """Scan through string looking for a match to the pattern, returning
a match object, or None if no match was found.""" a match object, or None if no match was found."""
......
...@@ -1061,6 +1061,30 @@ class ReTests(unittest.TestCase): ...@@ -1061,6 +1061,30 @@ class ReTests(unittest.TestCase):
self.assertEqual(m.group(1), "") self.assertEqual(m.group(1), "")
self.assertEqual(m.group(2), "y") self.assertEqual(m.group(2), "y")
def test_fullmatch(self):
# Issue 16203: Proposal: add re.fullmatch() method.
self.assertEqual(re.fullmatch(r"a", "a").span(), (0, 1))
self.assertEqual(re.fullmatch(r"a|ab", "ab").span(), (0, 2))
self.assertEqual(re.fullmatch(r".*?$", "abc").span(), (0, 3))
self.assertEqual(re.fullmatch(r".*?", "abc").span(), (0, 3))
self.assertEqual(re.fullmatch(r"a.*?b", "ab").span(), (0, 2))
self.assertEqual(re.fullmatch(r"a.*?b", "abb").span(), (0, 3))
self.assertEqual(re.fullmatch(r"a.*?b", "axxb").span(), (0, 4))
self.assertEqual(re.fullmatch(r"abc$", "abc\n"), None)
self.assertEqual(re.fullmatch(r"abc\Z", "abc\n"), None)
self.assertEqual(re.fullmatch(r"(?m)abc$", "abc\n"), None)
self.assertEqual(re.fullmatch(r"ab(?=c)cd", "abcd").span(), (0, 4))
self.assertEqual(re.fullmatch(r"ab(?<=b)cd", "abcd").span(), (0, 4))
self.assertEqual(re.fullmatch(r"(?=a|ab)ab", "ab").span(), (0, 2))
self.assertEqual(
re.compile(r"bc").fullmatch("abcd", pos=1, endpos=3).span(), (1, 3))
self.assertEqual(
re.compile(r".*?$").fullmatch("abcd", pos=1, endpos=3).span(), (1, 3))
self.assertEqual(
re.compile(r".*?").fullmatch("abcd", pos=1, endpos=3).span(), (1, 3))
def run_re_tests(): def run_re_tests():
from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR
if verbose: if verbose:
......
This diff is collapsed.
...@@ -89,6 +89,7 @@ typedef struct { ...@@ -89,6 +89,7 @@ typedef struct {
SRE_REPEAT *repeat; SRE_REPEAT *repeat;
/* hooks */ /* hooks */
SRE_TOLOWER_HOOK lower; SRE_TOLOWER_HOOK lower;
int match_all;
} SRE_STATE; } SRE_STATE;
typedef struct { typedef struct {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment