[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