Не может заставить работать не жадную игру - PullRequest
0 голосов
/ 13 мая 2018

В Python3.4 я использую библиотеку re (библиотека regex дает тот же результат), и я получаю результат, которого я не ожидаю.

У меня есть строка s ='ABC'.Я ожидаю, что следующее регулярное выражение:

re.match(r"^(.*?)(b?)(.*?)$", s).groups()

.. будет совпадать с тремя непустыми группами, а именно:

('a', 'b', 'c')

- потому что средняя часть шаблона жадная (b?).Вместо этого только последняя группа не пуста:

('', '', 'abc')

Я получаю одинаковый результат с обоими из следующих действий:

re.match(r"^(.*?)(b?)(.*?)$", s).groups()   #overt ^ and #
re.fullmatch("(.*?)(b?)(.*?)", s).groups()  #fullmatch()

Если я сделаю первую группу жадным совпадениемтогда результат будет:

('abc', '', '')

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

Регулярное выражение, которое я пытаюсь построить, конечно, сложнее, чем это, в противном случае я могу просто исключить b из левой и правой групп:

re.match(r"^([^b]*?)(b?)([^b]*?)$", s).groups()

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

I 'Мы смотрели на другие вопросы, помеченные для , и никто не отвечает на этот вопрос, хотя я подозреваю, что ответ ctwheels в python non-жадном совпадении стоит за моей проблемой (мешает необязательность первых двух группдвижок регулярных выражений от фактического сбоя до тех пор, пока он не достигнет конца строки, а затем ему нужно лишь немного откатить назад, чтобы получить безотказное совпадение).

Ответы [ 4 ]

0 голосов
/ 13 мая 2018

У вас есть хорошие ответы, но я собираюсь быть более конкретным в отношении этого требования:

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

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

^((?:(?!GROUP2).)*)(GROUP2)((?:!GROUP2).)*)$

Так что в случае GROUP2 be b это:

^((?:(?!b).)*)(b)((?:(?!b).)*)$

В мире регулярных выражений это называется закаленная точка .

Демонстрационная версия

0 голосов
/ 13 мая 2018

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

import re

def combo_finder(line):
    try:
        search = re.search("(foo|bar|baz)", line)
        start, end = search.start(1), search.end(1)
        return (line[:start], line[start:end], line[end:])
    except AttributeError:
        return (line, '', '')

test = ("afoob", "abarb", "afoo", "ab")

for s in test:
    print(s, combo_finder(s))

этот тестовый прогон дает

afoob ('a', 'foo', 'b')
abarb ('a', 'bar', 'b')
afoo ('a', 'foo', '')
ab ('ab', '', '')
0 голосов
/ 13 мая 2018

Отвечая самому себе (хотя, как я сказал в своем комментарии, я выбрал ответ Ахмеда в качестве ответа).Возможно, это поможет кому-то еще.Мое решение напоминает решение tdelaney, но использует if / else вместо try / исключением и получает ответ по-другому.Вот код:

rxRX = re.compile("^(.*)(foo|bar|baz)(.*)$")
Match = rxRX.match(sLine)
if Match:
     return [G for G in Match.groups()]
else: #rxRX didn't match, so just return the input:
     return [sLine]
0 голосов
/ 13 мая 2018

Я бы ожидал следующее регулярное выражение

re.match(r"^(.*?)(b?)(.*?)$", s).groups()

для сопоставления с тремя непустыми группами .. потому что средняя часть шаблона жадная

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

Вы специально указали регулярное выражение в первой группе, чтобы оно было lazy , что означает, что оно будет принимать наименьшее количество символов (которое в данном случае равно нулю) ) потому что ничто иное не заставляет его искать больше. Таким образом, хотя регулярное выражение во второй группе является жадным (то есть b?), оно по-прежнему не может соответствовать b, поскольку позиция по-прежнему равна 0.

Вы можете подтвердить это, заменив вторую группу на (.?), которая в этом случае будет соответствовать a, , а не b, как вы могли бы ожидать . Вот демо для ^(.*?)(.?)(.*?)$.

Теперь, если бы ваши правила запрещали отсутствие b, вы могли бы легко изменить свое регулярное выражение на ^(.*?)(b)(.*?)$, но, так как вы хотите, чтобы первая группа продолжала соответствовать , если b существует , но в то же время разрешено отсутствовать b (т. е. вторая группа может фактически быть пустой), тогда это решение не решает проблему.

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

^((?:.*?(?=b))|.*?)(b?)(.*?)$

Попробуйте онлайн .

Это продолжит сопоставление любых символов (используя .), пока не найдет b, а затем остановится, в противном случае (т. Е. Если нет b), оно будет прекращать сопоставление всякий раз, когда количество символов наименьшее можно найти (это оригинальное поведение). Другими словами, это гарантирует, что вторая группа не пуста , пока существует b .

Пожалуйста, дайте мне знать, если это не соответствует ни одному из ваших условий.

...