Python re.finditer match.groups() не содержит всех групп из соответствия

Я пытаюсь использовать регулярное выражение в Python для поиска и печати всех соответствующих строк из многострочного поиска. Текст, который я просматриваю, может иметь следующую структуру:

AAA
ABC1
ABC2
ABC3
AAA
ABC1
ABC2
ABC3
ABC4
ABC
AAA
ABC1
AAA

Из которого я хочу получить ABC * s, которые происходят по крайней мере один раз и предшествуют AAA.

Проблема в том, что, несмотря на то, что группа ломает то, что я хочу:

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")

Ответ 1

Вот ваше регулярное выражение:

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

Regular expression visualization

Демоверсия Debuggex

Ваша цель - захватить все ABC#, которые немедленно следуют за AAA. Как вы можете видеть в этой демоверсии Debuggex, все ABC# действительно совпадают (они выделены желтым цветом). Однако, поскольку только часть "что повторяется"

ABC[0-9]\r\n

находится захвачен (находится в круглых скобках) и его quantifier,

{1,}

не записывается, поэтому он вызывает все совпадения, кроме последнего, который должен быть отброшен. Чтобы получить их, вы также должны захватить квантификатор:

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

Regular expression visualization

Демоверсия Debuggex

Я поместил часть "то, что повторяется" (ABC[0-9]\r\n) в группу non-captureing. (Я также остановил захват 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 вниз)


Пожалуйста, рассмотрите возможность закладки часто задаваемых вопросов о регулярных выражениях стека для дальнейшего использования. Ссылки в этом ответе взяты из него.