Skip to content

Commit 497c42a

Browse files
committed
Implement missing index and count methods
1 parent 74480a7 commit 497c42a

File tree

4 files changed

+180
-1
lines changed

4 files changed

+180
-1
lines changed

Doc/library/re.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,19 @@ You can also destructure match objects with python's ``match`` statement::
15711571
that if *group* did not contribute to the match, this is ``(-1, -1)``.
15721572
*group* defaults to zero, the entire match.
15731573

1574+
.. method:: Match.index(value, start=0, stop=sys.maxsize, /)
1575+
1576+
Return the index of the first occurrence of the value among the matched groups.
1577+
1578+
Raises ValueError if the value is not present.
1579+
1580+
.. versionadded:: 3.14
1581+
1582+
.. method:: Match.count(value, /)
1583+
1584+
Return the number of occurrences of the value among the matched groups.
1585+
1586+
.. versionadded:: 3.14
15741587

15751588
.. attribute:: Match.pos
15761589

Lib/test/test_re.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,26 @@ def test_match_sequence(self):
621621
self.assertEqual(b, "b")
622622
self.assertEqual(c, "c")
623623

624+
self.assertIn("abc", m)
625+
self.assertIn("a", m)
626+
self.assertIn("b", m)
627+
self.assertIn("c", m)
628+
self.assertNotIn("123", m)
629+
630+
self.assertEqual(list(reversed(m)), ["c", "b", "a", "abc"])
631+
632+
self.assertEqual(m.index("abc"), 0)
633+
self.assertEqual(m.index("a"), 1)
634+
self.assertEqual(m.index("b"), 2)
635+
self.assertEqual(m.index("c"), 3)
636+
self.assertRaises(ValueError, m.index, "123")
637+
638+
self.assertEqual(m.count("abc"), 1)
639+
self.assertEqual(m.count("a"), 1)
640+
self.assertEqual(m.count("b"), 1)
641+
self.assertEqual(m.count("c"), 1)
642+
self.assertEqual(m.count("123"), 0)
643+
624644
match m:
625645
case [_, "a", "b", "c"]:
626646
pass

Modules/_sre/clinic/sre.c.h

Lines changed: 69 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_sre/sre.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,6 +2637,82 @@ _sre_SRE_Match_span_impl(MatchObject *self, PyObject *group)
26372637
return _pair(self->mark[index*2], self->mark[index*2+1]);
26382638
}
26392639

2640+
/*[clinic input]
2641+
_sre.SRE_Match.index
2642+
2643+
value: object
2644+
start: slice_index(accept={int}) = 0
2645+
stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize
2646+
/
2647+
2648+
Return the index of the first occurrence of the value among the matched groups.
2649+
2650+
Raises ValueError if the value is not present.
2651+
[clinic start generated code]*/
2652+
2653+
static PyObject *
2654+
_sre_SRE_Match_index_impl(MatchObject *self, PyObject *value,
2655+
Py_ssize_t start, Py_ssize_t stop)
2656+
/*[clinic end generated code: output=846597f6f96f829c input=7f41b5a99e0ad88e]*/
2657+
{
2658+
Py_ssize_t i;
2659+
2660+
if (start < 0) {
2661+
start += self->groups;
2662+
if (start < 0)
2663+
start = 0;
2664+
}
2665+
if (stop < 0) {
2666+
stop += self->groups;
2667+
}
2668+
else if (stop > self->groups) {
2669+
stop = self->groups;
2670+
}
2671+
for (i = start; i < stop; i++) {
2672+
PyObject* group = match_getslice_by_index(self, i, Py_None);
2673+
if (group == NULL)
2674+
return NULL;
2675+
int cmp = PyObject_RichCompareBool(group, value, Py_EQ);
2676+
Py_DECREF(group);
2677+
if (cmp > 0)
2678+
return PyLong_FromSsize_t(i);
2679+
else if (cmp < 0)
2680+
return NULL;
2681+
}
2682+
PyErr_SetString(PyExc_ValueError, "match.index(x): x not in match");
2683+
return NULL;
2684+
}
2685+
2686+
/*[clinic input]
2687+
_sre.SRE_Match.count
2688+
2689+
value: object
2690+
/
2691+
2692+
Return the number of occurrences of the value among the matched groups.
2693+
[clinic start generated code]*/
2694+
2695+
static PyObject *
2696+
_sre_SRE_Match_count_impl(MatchObject *self, PyObject *value)
2697+
/*[clinic end generated code: output=c0b81bdce5872620 input=b1f3372cfb4b8c74]*/
2698+
{
2699+
Py_ssize_t count = 0;
2700+
Py_ssize_t i;
2701+
2702+
for (i = 0; i < self->groups; i++) {
2703+
PyObject* group = match_getslice_by_index(self, i, Py_None);
2704+
if (group == NULL)
2705+
return NULL;
2706+
int cmp = PyObject_RichCompareBool(group, value, Py_EQ);
2707+
Py_DECREF(group);
2708+
if (cmp > 0)
2709+
count++;
2710+
else if (cmp < 0)
2711+
return NULL;
2712+
}
2713+
return PyLong_FromSsize_t(count);
2714+
}
2715+
26402716
static PyObject*
26412717
match_regs(MatchObject* self)
26422718
{
@@ -3247,6 +3323,8 @@ static PyMethodDef match_methods[] = {
32473323
_SRE_SRE_MATCH_START_METHODDEF
32483324
_SRE_SRE_MATCH_END_METHODDEF
32493325
_SRE_SRE_MATCH_SPAN_METHODDEF
3326+
_SRE_SRE_MATCH_INDEX_METHODDEF
3327+
_SRE_SRE_MATCH_COUNT_METHODDEF
32503328
_SRE_SRE_MATCH_GROUPS_METHODDEF
32513329
_SRE_SRE_MATCH_GROUPDICT_METHODDEF
32523330
_SRE_SRE_MATCH_EXPAND_METHODDEF

0 commit comments

Comments
 (0)