Как сопоставить регулярное выражение с группировкой с неизвестным количеством групп - PullRequest
23 голосов
/ 11 сентября 2009

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

... 
VALUE 100 234 568 9233 119
... 
VALUE 101 124 9223 4329 1559
...

Я хотел бы захватить список чисел, который появляется после первого вхождения строки, начинающейся с VALUE. я хочу, чтобы он возвратил ('100','234','568','9233','119'). Проблема в том, что я не знаю заранее, сколько будет чисел.

Я пытался использовать это как регулярное выражение:

VALUE (?:(\d+)\s)+

Это соответствует строке, но она захватывает только последнее значение, поэтому я просто получаю ('119',).

Ответы [ 6 ]

21 голосов
/ 11 сентября 2009

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

s = "VALUE 100 234 568 9233 119"
a = s.split()
if a[0] == "VALUE":
    print [int(x) for x in a[1:]]

Вы можете использовать регулярное выражение, чтобы увидеть, соответствует ли ваша строка ввода ожидаемому формату (используя регулярное выражение в вашем вопросе), затем вы можете запустить приведенный выше код, не проверяя "VALUE" и зная, что int(x) преобразование всегда будет успешным, поскольку вы уже подтвердили, что все следующие группы символов являются цифрами.

11 голосов
/ 11 сентября 2009
>>> import re
>>> reg = re.compile('\d+')
>>> reg.findall('VALUE 100 234 568 9233 119')
['100', '234', '568', '9223', '119']

Это не подтверждает, что ключевое слово «VALUE» появляется в начале строки, и не подтверждает, что между элементами есть ровно один пробел, но если вы можете сделать это как отдельный шаг (или вам вообще не нужно этого делать), тогда он найдет все последовательности цифр в любой строке.

3 голосов
/ 24 апреля 2017

Другой вариант, не описанный здесь, - это набор дополнительных групп захвата.

VALUE *(\d+)? *(\d+)? *(\d+)? *(\d+)? *(\d+)? *$

Это регулярное выражение охватывает до 5 цифр групп, разделенных пробелами. Если вам нужно больше потенциальных групп, просто скопируйте и вставьте больше *(\d+)? блоков.

2 голосов
/ 11 сентября 2009

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

matches = Regex.Match(log)

foreach (Match match in matches)
{
    submatches = Regex2.Match(match)
}

Это, конечно, также, если вы не хотите писать полный анализатор.

0 голосов
/ 13 августа 2018

Вы можете использовать re.match, чтобы сначала проверить, и вызвать re.split, чтобы использовать регулярное выражение в качестве разделителя для разделения.

>>> s = "VALUE 100 234 568 9233 119"
>>> sep = r"\s+"
>>> reg = re.compile(r"VALUE(%s\d+)+"%(sep)) # OR r"VALUE(\s+\d+)+"
>>> reg_sep = re.compile(sep)
>>> if reg.match(s): # OR re.match(r"VALUE(\s+\d+)+", s)
...     result = reg_sep.split(s)[1:] # OR re.split(r"\s+", s)[1:]
>>> result
['100', '234', '568', '9233', '119']

Разделитель "\s+" может быть более сложным.

0 голосов
/ 12 ноября 2017

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

VALUE((\s\d+)+)

Это должно привести к трем совпадениям: [0] вся строка, [1] материал после значения [2] последний пробел + значение.

[0] и [2] можно игнорировать, а затем [1] можно использовать со следующими параметрами:

\s(\d+)

Примечание: эти регулярные выражения не были проверены, но я надеюсь, что вы поняли идею.


Причина, по которой ответ Грега не работает для меня в том, что 2-я часть анализа более сложна, а не просто некоторые числа, разделенные пробелом.

Однако я бы честно согласился с решением Грега для этого вопроса (возможно, он гораздо эффективнее).

Я просто пишу этот ответ на случай, если кто-то ищет более изощренное решение, как мне нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...