Как соответствовать всему сообщению трассировки и не останавливаться раньше, используя регулярное выражение - PullRequest
0 голосов
/ 06 декабря 2018

Вот код Python:

st = """
Traceback (most recent call last):
  File "/builder_task.py", line 279, in do_one_task
    raise RecoverableBuildException("test error")
common.exceptions.BuildException: test error
"""

st2 = """
Traceback (most recent call last):
  File "/builder_task.py", line 279, in do_one_task
    raise RecoverableBuildException("test error")
common.exceptions.BuildException
"""

EXCEPTION_PATTERN = re.compile(
    r"Traceback \(most recent call last\):(?s).*?([\w\.]*(?:Exception|Error))(: .*?\n)?"
)
ex_match = EXCEPTION_PATTERN.findall(st)
ex_match2 = EXCEPTION_PATTERN.findall(st2)

Я ожидаю совпадения всей трассировки стека и захвата

("common.exceptions.BuildException", ": test error") для st ("common.exceptions.BuildException", "") для st2

однако этос самого начала совпал с «подъемом RecoverableBuildException» и захватил

('RecoverableBuildException', '') для st и ('', '') для st2

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Вы получаете только первую группу захвата, потому что вы соответствуете .*?, которое не является жадным, и затем захватываете в группе, совпадающей ноль или более раз, символ слова или точку [\w\.]*, за которыми следует либо Исключение, либо Ошибка.Первое совпадение - RecoverableBuildException, и захватывается группа 1.

Далее следует (: .*?\n)?, но после сопоставления с первой группой не существует совпадения :, поэтому вторая группа не совпадает.

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

Traceback \(most recent call last\):(?:\n.*)+?\n(.*?(?:Exception|Error):)\s*(.+)

Regex demo

Это будет соответствовать:

  • Traceback \(most recent call last\): Соответствовать буквально
  • (?:\n.*)+? Повторить для группы без захвата, соответствующей символу новой строки, за которым 0+ раз вводится любой символ
  • \n(.*?(?:Exception|Error):) Match newline and capturinggroup 0+ characters non greedy and than match Exception of Error followed by: `
  • \s* Совпадение 0+ пробельных символов
  • (.+) Захват группы 1+ раз любого символа

Например:

EXCEPTION_PATTERN = re.compile(
    r"Traceback \(most recent call last\):(?:\n.*)+?\n(.*?(?:Exception|Error):)\s*(.+)"
)
ex_match = EXCEPTION_PATTERN.findall(st)
print(ex_match)  # [('common.exceptions.BuildException:', 'test error')]
0 голосов
/ 06 декабря 2018

". ?"в середине вашего регулярного выражения не жадный: он будет соответствовать как можно меньше, чтобы удовлетворить выражение.Потому что "(:. ? \ N)?"является необязательным (это то, что делает заключительное '?': соответствует 0 или 1 из содержимого в скобках), "Exception" в конце "RecoverableBuildException" удовлетворяет выражению.

Есть два способа получитьрезультаты, которые вы хотите:

  • Удалить '?'от ".*?"в середине, чтобы сделать его жадным, чтобы он максимально соответствовал.
  • Переместите ':' перед последней скобкой, чтобы выражение заканчивалось на "| Ошибка)) :(. *? \ n)?»(или даже просто удалив все, кроме «:», поэтому он заканчивается на «| Ошибка)):»).
0 голосов
/ 06 декабря 2018

Я бы начал с понимания того, что любой приличный пользовательский класс Exception заканчивается либо «Exception», либо «Error» (хорошо, похоже, у вас это уже не работает).Теперь вы можете использовать re.search

>>> import re
>>> re.search(r'(?<=\n)(.*?(?:Exception|Error)):\s*(.*?)(?=\n|$)', st).groups()
('common.exceptions.BuildException', 'test error')

Это хороший первый шаг.Регулярное выражение выглядит следующим образом:

(?<=\n)              # lookbehind for newline
(                    # first capture group
.*?                  # match anything (non-greedy)
(?:Exception|Error)  # class name should end with "Exception" or "Error"
)
:                    # colon (literally)
\s*                  # zero or more spaces
(.*?)                # non-greedy match for the trailing text 
(?=\n|$)             # lookahead for EOL (EOS)

Вы можете изменить внешний вид, чтобы он соответствовал началу строки, если вы хотите.Измените (?<=\n) на (?:(?<=^)|(?<=\n)).

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