Подтвердить что ты не робот

Как сопоставить регулярное выражение с группировкой с неизвестным количеством групп

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

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

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

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

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

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

4b9b3361

Ответ 1

То, что вы ищете, это парсер, а не регулярное выражение. В вашем случае я бы рассмотрел использование очень простого парсера, 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) преобразование всегда будет успешным, так как вы уже подтвердили, что следующие группы символов - это все цифры.

Ответ 2

>>> import re
>>> reg = re.compile('\d+')
>>> reg.findall('VALUE 100 234 568 9233 119')
['100', '234', '568', '9223', '119']

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

Ответ 3

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

matches = Regex.Match(log)

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

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

Ответ 4

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

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

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

Ответ 5

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

VALUE((\s\d+)+)

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

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

\s(\d+)

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


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

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

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