Skip to content

Commit b191a01

Browse files
committed
re: Add support for finditer method
1 parent 0812ba1 commit b191a01

File tree

4 files changed

+105
-2
lines changed

4 files changed

+105
-2
lines changed

docs/library/re.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ Functions
140140

141141
Note: availability of this function depends on :term:`MicroPython port`.
142142

143+
.. function:: finditer(regex_str, string)
144+
145+
Return an iterator yielding ``Match`` objects over all non-overlapping
146+
matches for the RE pattern in string. The string is scanned
147+
left-to-right, and matches are returned in the order found.
148+
143149
.. data:: DEBUG
144150

145151
Flag value, display debug information about compiled expression.
@@ -156,10 +162,11 @@ Compiled regular expression. Instances of this class are created using
156162

157163
.. method:: regex.match(string, [pos, [endpos]])
158164
regex.search(string, [pos, [endpos]])
165+
regex.finditer(string, [pos, [endpos]])
159166
regex.sub(replace, string, count=0, flags=0, /)
160167

161-
Similar to the module-level functions :meth:`match`, :meth:`search`
162-
and :meth:`sub`.
168+
Similar to the module-level functions :meth:`match`, :meth:`search`,
169+
:meth:`finditer`, and :meth:`sub`.
163170
Using methods is (much) more efficient if the same regex is applied to
164171
multiple strings.
165172

extmod/modre.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,11 +422,75 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub_helper);
422422

423423
#endif
424424

425+
#if MICROPY_PY_RE_FINDITER
426+
427+
typedef struct _mp_re_finditer_it_t {
428+
mp_obj_base_t base;
429+
mp_fun_1_t iternext;
430+
mp_obj_t pattern;
431+
mp_obj_t str;
432+
mp_obj_t start;
433+
mp_obj_t end;
434+
} mp_re_finditer_it_t;
435+
436+
437+
static mp_obj_t mp_re_finditer_it_iternext(mp_obj_t self_in) {
438+
mp_re_finditer_it_t *self = MP_OBJ_TO_PTR(self_in);
439+
440+
mp_obj_t args[4] = {
441+
self->pattern,
442+
self->str,
443+
self->start,
444+
self->end
445+
};
446+
int n_args = (self->end == mp_const_none) ? 3 : 4;
447+
448+
mp_obj_t obj_match = re_exec(false, n_args, args);
449+
if (obj_match == mp_const_none) {
450+
return MP_OBJ_STOP_ITERATION;
451+
}
452+
453+
mp_obj_match_t *match = MP_OBJ_TO_PTR(obj_match);
454+
const char *begin = mp_obj_str_get_str(self->str);
455+
self->start = MP_OBJ_NEW_SMALL_INT(match->caps[1] - begin);
456+
return obj_match;
457+
}
458+
459+
static mp_obj_t re_finditer(size_t n_args, const mp_obj_t *args) {
460+
mp_re_finditer_it_t *iter = mp_obj_malloc(mp_re_finditer_it_t, &mp_type_polymorph_iter);
461+
iter->iternext = mp_re_finditer_it_iternext;
462+
iter->str = args[1];
463+
iter->start = MP_OBJ_NEW_SMALL_INT(0);
464+
iter->end = mp_const_none;
465+
466+
if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
467+
iter->pattern = args[0];
468+
if (n_args > 2) {
469+
iter->start = args[2];
470+
if (n_args > 3) {
471+
iter->end = args[3];
472+
}
473+
}
474+
}
475+
else {
476+
iter->pattern = MP_OBJ_TO_PTR(mod_re_compile(1, args));
477+
}
478+
479+
return MP_OBJ_FROM_PTR(iter);
480+
}
481+
482+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_finditer_obj, 2, 4, re_finditer);
483+
484+
#endif // MICROPY_PY_RE_FINDITER
485+
425486
#if !MICROPY_ENABLE_DYNRUNTIME
426487
static const mp_rom_map_elem_t re_locals_dict_table[] = {
427488
{ MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
428489
{ MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
429490
{ MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&re_split_obj) },
491+
#if MICROPY_PY_RE_FINDITER
492+
{ MP_ROM_QSTR(MP_QSTR_finditer), MP_ROM_PTR(&re_finditer_obj) },
493+
#endif
430494
#if MICROPY_PY_RE_SUB
431495
{ MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
432496
#endif
@@ -477,6 +541,9 @@ static const mp_rom_map_elem_t mp_module_re_globals_table[] = {
477541
{ MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
478542
{ MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
479543
{ MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
544+
#if MICROPY_PY_RE_FINDITER
545+
{ MP_ROM_QSTR(MP_QSTR_finditer), MP_ROM_PTR(&re_finditer_obj) },
546+
#endif
480547
#if MICROPY_PY_RE_SUB
481548
{ MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
482549
#endif

py/mpconfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,10 @@ typedef double mp_float_t;
16521652
#define MICROPY_PY_RE_MATCH_SPAN_START_END (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING)
16531653
#endif
16541654

1655+
#ifndef MICROPY_PY_RE_FINDITER
1656+
#define MICROPY_PY_RE_FINDITER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
1657+
#endif
1658+
16551659
#ifndef MICROPY_PY_RE_SUB
16561660
#define MICROPY_PY_RE_SUB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
16571661
#endif

tests/extmod/re_finditer.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
try:
2+
import re
3+
from re import finditer
4+
except ImportError:
5+
print("SKIP")
6+
raise SystemExit
7+
8+
ms = re.finditer(r'f[a-z]*', 'which foot or hand fell fastest')
9+
print(list(x.group(0) for x in ms))
10+
11+
p = re.compile(r'f[a-z]*')
12+
ms = p.finditer('which foot or hand fell fastest')
13+
print(list(x.group(0) for x in ms))
14+
15+
ms = p.finditer('which foot or hand fell fastest', 10)
16+
print(list(x.group(0) for x in ms))
17+
18+
ms = p.finditer('which foot or hand fell fastest', 10, 21)
19+
print(list(x.group(0) for x in ms))
20+
21+
ms = re.finditer(r'\s+', 'which foot or hand fell fastest')
22+
print(list(x.group(0) for x in ms))
23+
24+
ms = re.finditer(r'zz', 'which foot or hand fell fastest')
25+
print(list(x.group(0) for x in ms))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy