Skip to content

Commit 605bdae

Browse files
committed
Issue 24454: Improve the usability of the re match object named group API
1 parent a3c1728 commit 605bdae

File tree

4 files changed

+82
-1
lines changed

4 files changed

+82
-1
lines changed

Doc/library/re.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,22 @@ Match objects support the following methods and attributes:
10151015
'c3'
10161016

10171017

1018+
.. method:: match.__getitem__(g)
1019+
1020+
This is identical to ``m.group(g)``. This allows easier access to
1021+
an individual group from a match:
1022+
1023+
>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
1024+
>>> m[0] # The entire match
1025+
'Isaac Newton'
1026+
>>> m[1] # The first parenthesized subgroup.
1027+
'Isaac'
1028+
>>> m[2] # The second parenthesized subgroup.
1029+
'Newton'
1030+
1031+
.. versionadded:: 3.6
1032+
1033+
10181034
.. method:: match.groups(default=None)
10191035

10201036
Return a tuple containing all the subgroups of the match, from 1 up to however

Lib/test/test_re.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,50 @@ def __index__(self):
441441
self.assertEqual(m.group(2, 1), ('b', 'a'))
442442
self.assertEqual(m.group(Index(2), Index(1)), ('b', 'a'))
443443

444+
def test_match_getitem(self):
445+
pat = re.compile('(?:(?P<a1>a)|(?P<b2>b))(?P<c3>c)?')
446+
447+
m = pat.match('a')
448+
self.assertEqual(m['a1'], 'a')
449+
self.assertEqual(m['b2'], None)
450+
self.assertEqual(m['c3'], None)
451+
self.assertEqual('a1={a1} b2={b2} c3={c3}'.format_map(m), 'a1=a b2=None c3=None')
452+
self.assertEqual(m[0], 'a')
453+
self.assertEqual(m[1], 'a')
454+
self.assertEqual(m[2], None)
455+
self.assertEqual(m[3], None)
456+
with self.assertRaisesRegex(IndexError, 'no such group'):
457+
m['X']
458+
with self.assertRaisesRegex(IndexError, 'no such group'):
459+
m[-1]
460+
with self.assertRaisesRegex(IndexError, 'no such group'):
461+
m[4]
462+
with self.assertRaisesRegex(IndexError, 'no such group'):
463+
m[0, 1]
464+
with self.assertRaisesRegex(IndexError, 'no such group'):
465+
m[(0,)]
466+
with self.assertRaisesRegex(IndexError, 'no such group'):
467+
m[(0, 1)]
468+
with self.assertRaisesRegex(KeyError, 'a2'):
469+
'a1={a2}'.format_map(m)
470+
471+
m = pat.match('ac')
472+
self.assertEqual(m['a1'], 'a')
473+
self.assertEqual(m['b2'], None)
474+
self.assertEqual(m['c3'], 'c')
475+
self.assertEqual('a1={a1} b2={b2} c3={c3}'.format_map(m), 'a1=a b2=None c3=c')
476+
self.assertEqual(m[0], 'ac')
477+
self.assertEqual(m[1], 'a')
478+
self.assertEqual(m[2], None)
479+
self.assertEqual(m[3], 'c')
480+
481+
# Cannot assign.
482+
with self.assertRaises(TypeError):
483+
m[0] = 1
484+
485+
# No len().
486+
self.assertRaises(TypeError, len, m)
487+
444488
def test_re_fullmatch(self):
445489
# Issue 16203: Proposal: add re.fullmatch() method.
446490
self.assertEqual(re.fullmatch(r"a", "a").span(), (0, 1))

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ Core and Builtins
143143
Library
144144
-------
145145

146+
- Issue #24454: Regular expression match object groups are now
147+
accessible using __getitem__. "mo[x]" is equivalent to
148+
"mo.group(x)".
149+
146150
- Issue #10740: sqlite3 no longer implicitly commit an open transaction
147151
before DDL statements.
148152

Modules/_sre.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,12 @@ match_group(MatchObject* self, PyObject* args)
21212121
return result;
21222122
}
21232123

2124+
static PyObject*
2125+
match_getitem(MatchObject* self, PyObject* name)
2126+
{
2127+
return match_getslice(self, name, Py_None);
2128+
}
2129+
21242130
/*[clinic input]
21252131
_sre.SRE_Match.groups
21262132
@@ -2416,6 +2422,9 @@ PyDoc_STRVAR(match_group_doc,
24162422
Return subgroup(s) of the match by indices or names.\n\
24172423
For 0 returns the entire match.");
24182424

2425+
PyDoc_STRVAR(match_getitem_doc,
2426+
"__getitem__(name) <==> group(name).\n");
2427+
24192428
static PyObject *
24202429
match_lastindex_get(MatchObject *self)
24212430
{
@@ -2706,6 +2715,13 @@ static PyTypeObject Pattern_Type = {
27062715
pattern_getset, /* tp_getset */
27072716
};
27082717

2718+
/* Match objects do not support length or assignment, but do support
2719+
__getitem__. */
2720+
static PyMappingMethods match_as_mapping = {
2721+
NULL,
2722+
(binaryfunc)match_getitem,
2723+
NULL
2724+
};
27092725

27102726
static PyMethodDef match_methods[] = {
27112727
{"group", (PyCFunction) match_group, METH_VARARGS, match_group_doc},
@@ -2717,6 +2733,7 @@ static PyMethodDef match_methods[] = {
27172733
_SRE_SRE_MATCH_EXPAND_METHODDEF
27182734
_SRE_SRE_MATCH___COPY___METHODDEF
27192735
_SRE_SRE_MATCH___DEEPCOPY___METHODDEF
2736+
{"__getitem__", (PyCFunction)match_getitem, METH_O|METH_COEXIST, match_getitem_doc},
27202737
{NULL, NULL}
27212738
};
27222739

@@ -2751,7 +2768,7 @@ static PyTypeObject Match_Type = {
27512768
(reprfunc)match_repr, /* tp_repr */
27522769
0, /* tp_as_number */
27532770
0, /* tp_as_sequence */
2754-
0, /* tp_as_mapping */
2771+
&match_as_mapping, /* tp_as_mapping */
27552772
0, /* tp_hash */
27562773
0, /* tp_call */
27572774
0, /* tp_str */

0 commit comments

Comments
 (0)