Как сопоставить регулярное выражение с группировкой с неизвестным количеством групп
Я хочу сделать регулярное выражение (в Python) в выходной журнал программы. Журнал содержит несколько строк, которые выглядят так:
...
VALUE 100 234 568 9233 119
...
VALUE 101 124 9223 4329 1559
...
Я хотел бы захватить список чисел, который появляется после первого падения строки, которая начинается с VALUE. т.е. я хочу, чтобы он вернулся ('100','234','568','9233','119')
, Проблема в том, что я не знаю заранее, сколько будет номеров.
Я пытался использовать это как регулярное выражение:
VALUE (?:(\d+)\s)+
Это соответствует строке, но она захватывает только последнее значение, поэтому я просто получаю ('119',).
6 ответов
То, что вы ищете, это парсер, а не совпадение с регулярным выражением. В вашем случае, я бы рассмотрел использование очень простого парсера, 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)
преобразование всегда будет успешным, поскольку вы уже подтвердили, что все следующие группы символов являются цифрами.
>>> import re
>>> reg = re.compile('\d+')
>>> reg.findall('VALUE 100 234 568 9233 119')
['100', '234', '568', '9223', '119']
Это не подтверждает, что ключевое слово "VALUE" появляется в начале строки, и это не подтверждает, что между элементами имеется ровно один пробел, но если вы можете сделать это как отдельный шаг (или, если вы этого не сделаете) это вообще не нужно), тогда он найдет все последовательности цифр в любой строке.
Другой вариант, не описанный здесь, - это набор дополнительных групп захвата.
VALUE *(\d+)? *(\d+)? *(\d+)? *(\d+)? *(\d+)? *$
Это регулярное выражение охватывает до 5 групп цифр, разделенных пробелами. Если вам нужно больше потенциальных групп, просто скопируйте и вставьте больше *(\d+)?
блоки.
Вы можете просто запустить регулярное выражение основного совпадения, а затем запустить вторичное регулярное выражение для этих совпадений, чтобы получить числа:
matches = Regex.Match(log)
foreach (Match match in matches)
{
submatches = Regex2.Match(match)
}
Это, конечно, также, если вы не хотите писать полный анализатор.
У меня была такая же проблема, и я решил использовать два регулярных выражения: первое для соответствия всей интересующей меня группе и второе для анализа подгрупп. Например, в этом случае я бы начал с этого:
VALUE((\s\d+)+)
Это должно привести к трем совпадениям: [0] вся строка, [1] материал после значения [2] последний пробел + значение.
[0] и [2] можно игнорировать, а затем [1] можно использовать со следующим:
\s(\d+)
Примечание: эти регулярные выражения не были проверены, но я надеюсь, что вы поняли идею.
Причина, по которой ответ Грега не работает для меня, состоит в том, что 2-я часть анализа более сложна, а не просто некоторые числа, разделенные пробелом.
Тем не менее, я бы честно согласился с решением Грега по этому вопросу (возможно, он более эффективен).
Я просто пишу этот ответ на тот случай, если кто-то ищет более сложное решение, которое мне нужно.
Ты можешь использовать 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+"
может быть более сложным.