2016-07-29 2 views
1

Рассмотрит следующий (весьма упрощенная) строку:Regex для дополнительной концевой части подстроки

'a b a b c a b c a b c' 

Это повторяющийся рисунок 'a b c' за исключением того, в самом начале, где 'c' отсутствует.

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

[('a', 'b'), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')] 

Строки выше, таким образом, есть 4 матча из 'a b c' - хотя с первым матчем, как частный случай, так как 'c' отсутствует.

Моих Простейшие попытки, где я пытаюсь захватить 'a' и 'b' и использовать дополнительный захват для 'c':

re.findall(r'(a).*?(b).*?(c)?', 'a b a b c a b c a b c') 

я получаю:

[('a', 'b', ''), ('a', 'b', ''), ('a', 'b', ''), ('a', 'b', '')] 

Очевидно, он просто проигнорировал c. При использовании необязательного захвата для 'c' поиск пропускает преждевременно и пропускает 'a' и 'b' во втором 'a b c' -substring. В результате 3-х неправильных матчей:

[('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')] 

Я попробовал несколько других методов (например, '(?<=c)') безрезультатно.

Примечание: строка, приведенная выше, представляет собой лишь скелетный пример моей проблемы «реального мира», где три буквы выше сами являются строками (из длинного лог-файла) между другими строками и символами новой строки, из которых мне нужно извлечь названных групп.

Я использую Python 3.5.2 для Windows 7.

+0

Вы должны удалить пустые элементы кортежи «вручную» после того, как 'ре .findall' выполняет свою работу. –

+0

Вы уверены, что вам нужны регулярные выражения для анализа ваших журналов? –

+0

@WayneWerner Да :) Абсолютно необходимо. –

ответ

2

Так как ваш a, b и c являются заполнителями, и вы не можете знать, если таковые одиночные символы или последовательность символов, или что-нибудь еще, вы должны использовать закаленные жадные маркера чтобы убедиться, что шаблон не переполнение других матчей в той же строке, и так как c не обязательно, просто оберните его (?:...)? Необязательные захвата группы:

(a)(?:(?!a|b).)*(b)(?:(?:(?!a|b|c).)*(c))? 
    ^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^ ^

См regex demo

Детали:

  • (a) - Группа 1 захватывая некоторые a
  • (?:(?!a|b).)* - закаленного жадный маркер соответствует любому полукокса не Начинание a или b последовательности
  • (b) - 2-й группы, захватив некоторые b
  • (?: - начало необязательной группы, не связанной с захватом, реплика Ted 1 или 0 раз
    • (?:(?!a|b|c).)* - закаленного жадного маркера, который соответствует любому символу, но символ новой строки, который запускает a, b или c рисунка на
    • (c) - 3-я группа захвата некоторых c рисунка на
  • )? - конец необязательной группы, не связанной с захватом.

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

import re 
r = r'(a)(?:(?!a|b).)*(b)(?:(?:(?!a|b|c).)*(c))?' 
s = 'a b a b c a b c a b c' 
# print(re.findall(r,s)) 
# That one is bad: [('a', 'b', ''), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')] 
print([(a,b,c) if c else (a,b) for a,b,c in re.findall(r,s)]) 
# This one is good: [('a', 'b'), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')] 

См Python demo

+0

Спасибо. Регулярные выражения хороши для простых вещей (по крайней мере).То, что я пытаюсь сделать, не может, я думаю, выполняться по правилам конечных автоматов (для этого требуется больше ветвящейся логики). Я только что пробовал ваш подход, и он все еще пропускает части. Я буду искать другой подход. Принято, потому что я узнал что-то новое :-) –

+0

Ну, вы только разместили очень упрощенный образец, который я пытался обобщить как можно больше. Регулярные выражения требуют точности и требуют точных точных требований. С наилучшими пожеланиями. –

Смежные вопросы