Python中re.finditer match.groups()不包含match中的所有组。

3
我正在尝试使用Python中的正则表达式在多行搜索中查找并打印所有匹配行。我要搜索的文本可能具有以下示例结构:
AAA
ABC1
ABC2
ABC3
AAA
ABC1
ABC2
ABC3
ABC4
ABC
AAA
ABC1
AAA
我想从中检索至少出现一次且在AAA之前的ABC*s。
问题是,尽管组捕获了我想要的内容:
match = <_sre.SRE_Match object; span=(19, 38), match='AAA\nABC2\nABC3\nABC4\n'>

我只能访问到该组的最后一个匹配项:

match groups = ('AAA\n', 'ABC4\n')

以下是我用于解决这个问题的示例代码。
#! python
import sys
import re
import os

string = "AAA\nABC1\nABC2\nABC3\nAAA\nABC1\nABC2\nABC3\nABC4\nABC\nAAA\nABC1\nAAA\n"
print(string)

p_MATCHES = []
p_MATCHES.append( (re.compile('(AAA\n)(ABC[0-9]\n){1,}')) ) #   
matches = re.finditer(p_MATCHES[0],string)

for match in matches:
    strout = ''
    gr_iter=0
    print("match = "+str(match))
    print("match groups = "+str(match.groups()))
    for group in match.groups():
    gr_iter+=1
    sys.stdout.write("TEST GROUP:"+str(gr_iter)+"\t"+group) # test output
    if group is not None:
        if group != '':
            strout+= '"'+group.replace("\n","",1)+'"'+'\n'
sys.stdout.write("\nCOMPLETE RESULT:\n"+strout+"====\n")
2个回答

7

这是您的正则表达式:

(AAA\r\n)(ABC[0-9]\r\n){1,}

Regular expression visualization

Debuggex演示

您的目标是捕获紧随AAA之后的所有ABC#。如您在这个Debuggex演示中所见,所有的ABC#都被匹配了(它们被用黄色突出显示)。然而,由于只有“正在重复的内容”部分

ABC[0-9]\r\n

正在捕获(在括号内),并且它的量词

{1,}

没有被捕获,这导致所有匹配(除了最后一个)都被丢弃。要获取它们,您还必须捕获量词。
AAA\r\n((?:ABC[0-9]\r\n){1,})

Regular expression visualization

Debuggex演示

我将“被重复的内容”部分 (ABC[0-9]\r\n) 放入了一个 非捕获组 中。(我也停止了对 AAA 的捕获,因为你似乎不需要它。)

捕获的文本可以在换行符上分割,这将给您所有所需的片段。

(请注意,\n 本身在 Debuggex 中无法工作。它需要 \r\n。)


这是一个解决方法。并非所有正则表达式引擎都支持通过重复捕获进行迭代的功能(哪些支持...?)。更常见的方法是在找到每个匹配项时循环并处理它们。以下是Java的一个示例:
   import java.util.regex.*;

public class RepeatingCaptureGroupsDemo {
   public static void main(String[] args) {
      String input = "I have a cat, but I like my dog better.";

      Pattern p = Pattern.compile("(mouse|cat|dog|wolf|bear|human)");
      Matcher m = p.matcher(input);

      while (m.find()) {
         System.out.println(m.group());
      }
   }
}

输出:
cat
dog

(来自http://ocpsoft.org/opensource/guide-to-regular-expressions-in-java-part-1/,大约下降了1/4)


请考虑将Stack Overflow Regular Expressions FAQ加入书签以备将来参考。 这个答案中的链接都来自它。

这是一个值得的解决方法。 我想要的是获得一组可迭代的分组,例如:匹配分组 = ('AAA', 'ABC1', 'ABC2', 'ABC3', ...)我用这种解决方案得到的是匹配分组 = ('AAA', 'ABC1 \n ABC2 \n ABC3 \n') - glamredhel
2
抱歉,我尝试点赞但是声望不够。这个答案确实有帮助。我已经内置了另一组循环来解决问题。虽然不完全是我想要的解决方案,但仍然是一个解决方案。 - glamredhel

0

你想以最贪婪的方式返回在一个 AAA\n 后连续出现的 ABC\n 的模式。你只想要连续的 ABC\n 组而不是包括最近的 ABC\n 的元组。因此,在你的正则表达式中,要排除组内的子组。 注意模式,编写表示整个字符串的模式。

AAA\n(ABC[0-9]\n)+

然后使用 () 捕获您感兴趣的内容,同时记得排除子组。

AAA\n((?:ABC[0-9]\n)+)

你可以使用findall()或finditer()。当你处理多个捕获时,我发现findIter更容易上手。

finditer:-
import re
matches_iter = re.finditer(r'AAA\n((?:ABC[0-9]\n)+)', string)

[print(i.group(1)) for i in matches_iter]

findall函数使用原始的{1,},因为它是+符号的更详细的形式。 :-

matches_all = re.findall(r'AAA\n((?:ABC[0-9]\n){1,})', string)

[[print(x) for x in y.split("\n")] for y in matches_all]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接