[issue9529] Make re match object iterable

Serhiy Storchaka report at bugs.python.org
Fri Aug 1 14:02:14 CEST 2014


Serhiy Storchaka added the comment:

Yes, but the purpose of this feature is to simplify the use of finditer() in 
the "for" loop.

>>> import re
>>> for k, v in re.finditer(r"(\w+):?(\w+)?", "ab:cd\nef\n"):
...     print(k, v)
... 
ab cd
ef None

Currently you should either unpack manually:

    for m in re.finditer(...):
        k, v = m.groups()
        ...

This way doesn't work well with comprehensions.

Or use the operator module:

    import operator
    for k, v in map(operator.methodcaller('groups'), re.finditer(...)):
        ...

This way is too verbose and unclear.

Sorry, previous version of the patch had reference leak.

----------
Added file: http://bugs.python.org/file36193/re_matchobj_iterable.patch

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue9529>
_______________________________________
-------------- next part --------------
diff -r 4c1d543135ef Doc/library/re.rst
--- a/Doc/library/re.rst	Thu Jul 31 23:58:27 2014 -0500
+++ b/Doc/library/re.rst	Fri Aug 01 14:57:03 2014 +0300
@@ -873,6 +873,15 @@
    if match:
        process(match)
 
+Match objects are iterable and can be unpacked.  ``iter(match)`` is equivalent
+to ``iter(match.groups())``.  For example:
+
+   >>> [(k, v) for k, v in re.finditer(r"(\w+):?(\w+)?", "ab:cd, ef")]
+   [('ab', 'cd'), ('ef', None)]
+
+.. versionadded:: 3.5
+   Match objects are now iterable.
+
 Match objects support the following methods and attributes:
 
 
diff -r 4c1d543135ef Lib/test/test_re.py
--- a/Lib/test/test_re.py	Thu Jul 31 23:58:27 2014 -0500
+++ b/Lib/test/test_re.py	Fri Aug 01 14:57:03 2014 +0300
@@ -349,6 +349,18 @@
                          (None, 'b', None))
         self.assertEqual(pat.match('ac').group(1, 'b2', 3), ('a', None, 'c'))
 
+    def test_re_match_iter(self):
+        pat = re.compile(r'(\w+):(\w+)?:(\w+)')
+        m = pat.match('ab::cd=')
+        it = iter(m)
+        self.assertEqual(next(it), 'ab')
+        self.assertEqual(next(it), None)
+        self.assertEqual(next(it), 'cd')
+        self.assertRaises(StopIteration, next, it)
+        self.assertEqual(list(m), ['ab', None, 'cd'])
+        x, y, z = m
+        self.assertEqual((x, y, z), ('ab', None, 'cd'))
+
     def test_re_fullmatch(self):
         # Issue 16203: Proposal: add re.fullmatch() method.
         self.assertEqual(re.fullmatch(r"a", "a").span(), (0, 1))
@@ -896,6 +908,10 @@
         self.assertEqual([item.group(0) for item in iter],
                          ["::", "::"])
 
+        iter = re.finditer(r"(\w+):?(\w+)?", "ab:cd\nef\n")
+        self.assertEqual([(k, v) for k, v in iter],
+                         [('ab', 'cd'), ('ef', None)])
+
     def test_bug_926075(self):
         self.assertTrue(re.compile('bug_926075') is not
                      re.compile(b'bug_926075'))
diff -r 4c1d543135ef Modules/_sre.c
--- a/Modules/_sre.c	Thu Jul 31 23:58:27 2014 -0500
+++ b/Modules/_sre.c	Fri Aug 01 14:57:03 2014 +0300
@@ -2080,6 +2080,31 @@
 }
 
 static PyObject*
+match_iter(MatchObject* self)
+{
+    PyObject *result, *iter;
+    Py_ssize_t index;
+
+    result = PyTuple_New(self->groups-1);
+    if (!result)
+        return NULL;
+
+    for (index = 1; index < self->groups; index++) {
+        PyObject* item;
+        item = match_getslice_by_index(self, index, Py_None);
+        if (!item) {
+            Py_DECREF(result);
+            return NULL;
+        }
+        PyTuple_SET_ITEM(result, index-1, item);
+    }
+
+    iter = PyObject_GetIter(result);
+    Py_DECREF(result);
+    return iter;
+}
+
+static PyObject*
 match_groups(MatchObject* self, PyObject* args, PyObject* kw)
 {
     PyObject* result;
@@ -2478,7 +2503,7 @@
     0,                          /* tp_clear */
     0,                          /* tp_richcompare */
     0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
+    (getiterfunc)match_iter,    /* tp_iter */
     0,                          /* tp_iternext */
     match_methods,              /* tp_methods */
     match_members,              /* tp_members */


More information about the Python-bugs-list mailing list