2012-05-02 3 views
8

Я прочитал все связанные сообщения и просмотрел интернет, но это действительно избивает меня.Как сделать отрицательный взгляд Python менее жадным?

У меня есть текст, содержащий дату.
Я хотел бы зафиксировать дату, но не если ей предшествует определенная фраза.

Простое решение - добавить отрицательный lookbehind в мой RegEx.

Вот несколько примеров (с помощью findall).
Я только хочу зафиксировать дату, если ей не предшествует фраза «от».

19-2-11
что-то что-то 15-4-11
такие и такие, как из 29-5-11

Вот мое регулярное выражение:

(?<!as of)(\d{1,2}-\d{1,2}-\d{2}) 

Ожидаемые результаты:

['19 -2-11 ']
['15 -4-11']
[]

Фактические результаты:

['19] -2-11'
['15 -4-11 ']
[' 9-5-11' ]

Обратите внимание, что это-не 29. Если я изменяю \d{1,2} к чему-то твердому, как \d{2} на первый шаблоне :

bad regex for testing: (?<!as of)(\d{2}-\d{1,2}-\d{2}) 

Затем я получаю ожидаемые результаты. Конечно, это не хорошо, потому что я хотел бы сопоставлять 2-значные дни, а также однозначные дни.

По-видимому, мой отрицательный lookbehind - это жадность - moreso, чем мой захват даты, поэтому он крадет цифру из нее и терпит неудачу. Я пробовал все средства для исправления жадности, о которой я могу думать, но я просто не знаю, чтобы исправить это.

Я бы хотел, чтобы мой захват даты соответствовал максимальной жадности, а затем применялся мой негативный вид. Это возможно? Моя проблема казалась хорошим использованием негативных взглядов и не слишком сложной. Я уверен, что смогу сделать это по-другому, если нужно, но я хотел бы узнать, как это сделать.

Как сделать отрицательный взгляд Python менее жадным?

ответ

1

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

Он продвигается по фразе such and such as of 29-5-11, успешно совпадающий с (?<!as of), но не соответствует \d{1,2}.

Но тогда двигатель находит себя в положении such and such as of !29-5-11 (с пометкой !). Но здесь он не соответствует (?<!as of).

И он переходит на следующую позицию: such and such as of 2!9-5-11. Где он успешно соответствует (?<!as of), а затем \d{1,2}.

Как этого избежать?

Общее решение состоит в том, чтобы сформулировать шаблон как можно яснее.

В этом случае я бы добавил цифру с необходимым пространством или началом строки.

(?<!as of)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2}) 

Решение Mark Byers также очень хорошее.

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

Кстати, решение, которое я дал выше, не работает, если есть 2 или более пробелов. Это не работает, потому что здесь первое место соответствует such and such as of ! 29-5-11 с вышеупомянутым рисунком.

Что можно сделать, чтобы избежать этого?

К сожалению, lookback в Python-двигателе regex не поддерживает кванторы + или *.

Я думаю, что самое простое решение было бы, чтобы убедиться, не пробелы до (?:^|\s+) (meaing что все пространства потребляются (?:^|\s+) прямо после текста nonspace (и в случае, если текст as of, прекратить продвижение и возвратиться к следующая исходная позиция начала поиска сначала на следующей позиции искомого текста).

re.search(r'(?<!as of)(?<!\s)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2})','such and such as of 29-5-11').group(1) 
+0

Это фантастика, я нахожу '(?:^| \ S +)' и ваше объяснение очень ясное. Я чувствую, что на мой вопрос ответили.:) Чисто ради знания и не необходимости Я хотел бы узнать, как изменить это, поэтому '\ s' является необязательным, так что' something something15-4-11' будет соответствовать, но я могу быть в состоянии это сам. Спасибо! –

+0

@ChristopherGalpin Я думаю, что это может быть достигнуто очень легко, используя '*' (от 0 до бесконечности вхождения) вместо '+' (от 1 до бесконечности вхождения) в этой части шаблона: '(?:^| \ S +) ' – ovgolovin

+0

Я надеялся, что это так просто, но, видимо, нет, ломает совпадение« как », так же, как и исходный вопрос. –

7

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

Чтобы исправить это может потребовать границу слова непосредственно перед матчем:

(?<!as of)\b(\d{1,2}-\d{1,2}-\d{2}) 
#   ^^ add this 
+0

Ну, это сработало, и теперь я чувствую себя глупым. :) Спасибо. у! Я знаю, что это расширяет исходный вопрос, но есть ли простой способ, которым я могу погладить пробелы между фразой и датой? Слева должна быть фиксированной ширины, чтобы она не могла туда попасть, но добавление \ s * рядом с датой, похоже, воскрешает проблему. –

+2

Как насчет этого: '(?

+0

Спасибо, я нахожу это очень образованным. –

-1

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

+2

«Фред был боссом вчерашнего дня. У власти с 31-12-11, ...» => FAIL –

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