diff --git a/CHANGES.md b/CHANGES.md index d1910513da58..bac1b537871a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -82,6 +82,7 @@ `valueMapper`, `topicNameMapper`, or providing a `ConnectionFactory` must update imports from `javax.jms.*` to `jakarta.jms.*`. The module now requires Java 17 at runtime ([#38729](https://github.com/apache/beam/issues/38729)). * (Python) `Regex.find_all` with `group=Regex.ALL` now returns every group, as `(match, group1, group2, ...)`, instead of only group 1, and with `outputEmpty=False` it drops a match only when the whole match is empty, matching the `group=0` behavior ([#40399](https://github.com/apache/beam/pull/40399)). +* (Python) `Regex.all_matches` now returns every group of the regex, instead of failing with a `TypeError` when the regex has no groups and dropping nested or unmatched trailing groups ([#40562](https://github.com/apache/beam/issues/40562)). ## Deprecations diff --git a/sdks/python/apache_beam/transforms/util.py b/sdks/python/apache_beam/transforms/util.py index b7885544dbfb..c8c7cc86d718 100644 --- a/sdks/python/apache_beam/transforms/util.py +++ b/sdks/python/apache_beam/transforms/util.py @@ -2156,7 +2156,9 @@ def _process(element): def all_matches(pcoll, regex): """ Returns all matches (groups) if zero or more characters at the beginning - of string match the regular expression. + of string match the regular expression. Each output is a list of the + entire match followed by every group of the regex, with None for a group + that did not participate in the match. Args: regex: the regular expression string or (re.compile) pattern. @@ -2166,7 +2168,7 @@ def all_matches(pcoll, regex): def _process(element): m = regex.match(element) if m: - yield [m.group(ix) for ix in range(m.lastindex + 1)] + yield [m.group(), *m.groups()] return pcoll | FlatMap(_process) diff --git a/sdks/python/apache_beam/transforms/util_test.py b/sdks/python/apache_beam/transforms/util_test.py index bba09245a0fb..1e3db695e074 100644 --- a/sdks/python/apache_beam/transforms/util_test.py +++ b/sdks/python/apache_beam/transforms/util_test.py @@ -2854,6 +2854,22 @@ def test_all_matched_pattern(self): ["z z", "z", "z"]] assert_that(result, equal_to(expected_result)) + def test_all_matched_returns_every_group(self): + with TestPipeline() as p: + pcol = (p | beam.Create(["ab"])) + assert_that( + pcol | 'nested groups' >> util.Regex.all_matches("((a)(b))"), + equal_to([["ab", "ab", "a", "b"]]), + label='CheckNestedGroups') + assert_that( + pcol | 'optional group' >> util.Regex.all_matches("(a)(c)?"), + equal_to([["a", "a", None]]), + label='CheckOptionalGroup') + assert_that( + pcol | 'no groups' >> util.Regex.all_matches("a+"), + equal_to([["a"]]), + label='CheckNoGroups') + def test_match_group_kv(self): with TestPipeline() as p: result = (