Захват повторяющегося шаблона в Python - PullRequest
2 голосов
/ 15 марта 2020

Я пытаюсь реализовать какое-то поведение, подобное уценке, для Python средства форматирования журнала.

Давайте возьмем эту строку в качестве примера:

**This is a warning**: Virus manager __failed__

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

\033[33m\033[1mThis is a warning\033[0m: Virus manager \033[4mfailed\033[0m\033[0m

Но это должно быть сжато до

\033[33;1mThis is a warning\033[0m: Virus manager \033[4mfailed\033[0m

Я попробовал это, кроме многих других нерабочих решений:

(\\033\[([\d]+)m){2,} => Захват: \033[33m\033[1m с g1 '\ 033 [1m' и g2 '1' и \033[0m\033[0m с g1 '\ 033 [0m' и g2 '0'

(\\033\[([\d]+)m)+ много результатов, не в порядке

(?:(\\033\[([\d]+)m)+) много результатов, хотя это рекомендуемый способ для повторных паттернов если я правильно понял, не в порядке

и другие ..

Моя цель - получить как результат:

Ввод \033[33m\033[1mThis is a warning\033[0m: Virus manager \033[4mfailed\033[0m\033[0m

Ввод

Матч 1 033[33m\033[1m

Группа1 : 33

Группа2 : 1

Матч 2 033[0m\033[0m

Группа1 : 0

Group2 : 0

Другими словами, перехватывайте те, которые «дублированы», а не одни, поэтому я могу объединить их с подпрограммой регулярного выражения.

Ответы [ 3 ]

1 голос
/ 15 марта 2020

Шаблоны в строке, которую нужно изменить, не были понятны из вопроса. Например, 033 исправлено или это может быть 025 или даже 25? Я сделал некоторые предположения при использовании регулярного выражения

r" ^(\\0(\d+)\[\2)[a-z]\\0\2\[(\d[a-z].+)

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

Демо

Регулярное выражение выполняет следующие операции:

^           # match beginning of line
(           # begin cap grp 1
  \\0       # match '\0'
  (\d+)     # match 1+ digits in cap grp 2
  \[        # match '['
  \2        # match contents of cap grp 2
)           # end cap grp 1
[a-z]       # match a lc letter
\\0         # match '\0'      
\2          # match contents of cap grp 2
\[          # match '['
(\d[a-z].+) # match a digit, then lc letter then 1+ chars to the
            #   end of the line in cap grp 3

Как видите, часть строки, захваченной в группе 1, равна

\033[33

Я предположил, что часть этой строки, которая сейчас 033, должна состоять из двух или более цифр, начинающихся с нуля, а второе появление строки цифр состоит из тех же цифр после ноль. Это делается путем захвата цифр, следующих за «0» (33) в группе захвата 2, а затем с использованием обратной ссылки \2.

Следующая часть строки должна быть заменена и, следовательно, не захвачено:

m\\033[

Я предположил, что m должно быть одной строчной буквой (или литералом m?), обратная косая черта sh и ноль, и требуется, и следующие цифры должны снова соответствовать содержимому группы захвата 2.

Остальная часть строки,

1mThis is a warning\033[0m: Virus manager \033[4mfailed\033[0m\033[0m

, записывается в группе захвата 3. Здесь я предположил, что она начинается с одной ди git (возможно, это должно быть \d+), за которым следует одна буква в нижнем регистре, которая не должна совпадать с буквой в нижнем регистре, сопоставленной ранее (хотя это может быть применено с другой группой захвата). В этот момент я сопоставляю оставшуюся часть строки с .+, отказавшись от соответствующих шаблонов в этой части строки.

В качестве альтернативы можно иметь только две группы захвата, группу захвата, которая сейчас # 2 становится № 1, а № 2 - частью строки, которая должна быть заменена точкой с запятой.

1 голос
/ 16 марта 2020

Вы хотите сопоставлять последовательно повторяющиеся \033[\d+m фрагменты текста и соединять числа после [ точкой с запятой.

Вы можете использовать

re.sub(r'(?:\\033\[\d+m){2,}', lambda m: r'\033['+";".join(set(re.findall(r"\[(\d+)", m.group())))+'m', text)

См. Python демоверсия онлайн

Шаблон (?:\\033\[\d+m){2,} будет соответствовать двум или более последовательностям \033[ + одной или нескольким цифрам + m фрагментам текста, а затем совпадение будет передается в лямбда-выражение, где выходные данные будут: 1) \033[, 2) все числа после [, извлеченные с помощью re.findall(r"\[(\d+)", m.group()) и дедуплицированные с помощью set, а затем 3) m.

0 голосов
/ 15 марта 2020

Это довольно просто для случаев, которые вы описываете здесь; просто напишите слева направо, что вы хотите сопоставить и захватить. Повторные блоки захвата вам здесь не помогут, потому что в результате будут возвращены только последние полученные значения.

\\033\[(\d+)m\\033\[(\d+)m
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...