]> granicus.if.org Git - python/commitdiff
Issue 24454: Improve the usability of the re match object named group API
authorEric V. Smith <eric@trueblade.com>
Sun, 11 Sep 2016 12:55:43 +0000 (08:55 -0400)
committerEric V. Smith <eric@trueblade.com>
Sun, 11 Sep 2016 12:55:43 +0000 (08:55 -0400)
Doc/library/re.rst
Lib/test/test_re.py
Misc/NEWS
Modules/_sre.c

index 87cd5536010c79c84a4850d2a2279dd839825755..8ffcd9a82073558d41936e2d288f9db2f72087a9 100644 (file)
@@ -1015,6 +1015,22 @@ Match objects support the following methods and attributes:
       'c3'
 
 
+.. method:: match.__getitem__(g)
+
+   This is identical to ``m.group(g)``.  This allows easier access to
+   an individual group from a match:
+
+      >>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
+      >>> m[0]       # The entire match
+      'Isaac Newton'
+      >>> m[1]       # The first parenthesized subgroup.
+      'Isaac'
+      >>> m[2]       # The second parenthesized subgroup.
+      'Newton'
+
+   .. versionadded:: 3.6
+
+
 .. method:: match.groups(default=None)
 
    Return a tuple containing all the subgroups of the match, from 1 up to however
index 79a7a057a04e7438ba1d56535bb4810312a3698b..eb1aba39c31fd041c7a071ab9b2df9d9b7134010 100644 (file)
@@ -441,6 +441,50 @@ class ReTests(unittest.TestCase):
         self.assertEqual(m.group(2, 1), ('b', 'a'))
         self.assertEqual(m.group(Index(2), Index(1)), ('b', 'a'))
 
+    def test_match_getitem(self):
+        pat = re.compile('(?:(?P<a1>a)|(?P<b2>b))(?P<c3>c)?')
+
+        m = pat.match('a')
+        self.assertEqual(m['a1'], 'a')
+        self.assertEqual(m['b2'], None)
+        self.assertEqual(m['c3'], None)
+        self.assertEqual('a1={a1} b2={b2} c3={c3}'.format_map(m), 'a1=a b2=None c3=None')
+        self.assertEqual(m[0], 'a')
+        self.assertEqual(m[1], 'a')
+        self.assertEqual(m[2], None)
+        self.assertEqual(m[3], None)
+        with self.assertRaisesRegex(IndexError, 'no such group'):
+            m['X']
+        with self.assertRaisesRegex(IndexError, 'no such group'):
+            m[-1]
+        with self.assertRaisesRegex(IndexError, 'no such group'):
+            m[4]
+        with self.assertRaisesRegex(IndexError, 'no such group'):
+            m[0, 1]
+        with self.assertRaisesRegex(IndexError, 'no such group'):
+            m[(0,)]
+        with self.assertRaisesRegex(IndexError, 'no such group'):
+            m[(0, 1)]
+        with self.assertRaisesRegex(KeyError, 'a2'):
+            'a1={a2}'.format_map(m)
+
+        m = pat.match('ac')
+        self.assertEqual(m['a1'], 'a')
+        self.assertEqual(m['b2'], None)
+        self.assertEqual(m['c3'], 'c')
+        self.assertEqual('a1={a1} b2={b2} c3={c3}'.format_map(m), 'a1=a b2=None c3=c')
+        self.assertEqual(m[0], 'ac')
+        self.assertEqual(m[1], 'a')
+        self.assertEqual(m[2], None)
+        self.assertEqual(m[3], 'c')
+
+        # Cannot assign.
+        with self.assertRaises(TypeError):
+            m[0] = 1
+
+        # No len().
+        self.assertRaises(TypeError, len, m)
+
     def test_re_fullmatch(self):
         # Issue 16203: Proposal: add re.fullmatch() method.
         self.assertEqual(re.fullmatch(r"a", "a").span(), (0, 1))
index ce7562f2a567188aad8ea0214457263cc38b8323..25bf7cca94a0a3602d167f187c96d946409be4ef 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -143,6 +143,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #24454: Regular expression match object groups are now
+  accessible using __getitem__.  "mo[x]" is equivalent to
+  "mo.group(x)".
+
 - Issue #10740: sqlite3 no longer implicitly commit an open transaction
   before DDL statements.
 
index afa90999ac6af1c840dad914c88e6623a008e2fe..e4372bedb6e7afdf23af3d40e26ec6899ea9a21a 100644 (file)
@@ -2121,6 +2121,12 @@ match_group(MatchObject* self, PyObject* args)
     return result;
 }
 
+static PyObject*
+match_getitem(MatchObject* self, PyObject* name)
+{
+    return match_getslice(self, name, Py_None);
+}
+
 /*[clinic input]
 _sre.SRE_Match.groups
 
@@ -2416,6 +2422,9 @@ PyDoc_STRVAR(match_group_doc,
     Return subgroup(s) of the match by indices or names.\n\
     For 0 returns the entire match.");
 
+PyDoc_STRVAR(match_getitem_doc,
+"__getitem__(name) <==> group(name).\n");
+
 static PyObject *
 match_lastindex_get(MatchObject *self)
 {
@@ -2706,6 +2715,13 @@ static PyTypeObject Pattern_Type = {
     pattern_getset,                     /* tp_getset */
 };
 
+/* Match objects do not support length or assignment, but do support
+   __getitem__. */
+static PyMappingMethods match_as_mapping = {
+    NULL,
+    (binaryfunc)match_getitem,
+    NULL
+};
 
 static PyMethodDef match_methods[] = {
     {"group", (PyCFunction) match_group, METH_VARARGS, match_group_doc},
@@ -2717,6 +2733,7 @@ static PyMethodDef match_methods[] = {
     _SRE_SRE_MATCH_EXPAND_METHODDEF
     _SRE_SRE_MATCH___COPY___METHODDEF
     _SRE_SRE_MATCH___DEEPCOPY___METHODDEF
+    {"__getitem__", (PyCFunction)match_getitem, METH_O|METH_COEXIST, match_getitem_doc},
     {NULL, NULL}
 };
 
@@ -2751,7 +2768,7 @@ static PyTypeObject Match_Type = {
     (reprfunc)match_repr,       /* tp_repr */
     0,                          /* tp_as_number */
     0,                          /* tp_as_sequence */
-    0,                          /* tp_as_mapping */
+    &match_as_mapping,          /* tp_as_mapping */
     0,                          /* tp_hash */
     0,                          /* tp_call */
     0,                          /* tp_str */