2013-09-14 1 views
0

Я хочу использовать re.findall в python для соответствия всем минимальным строкам между токенами {START} и {END}.python regex, чтобы соответствовать всем минимальным строкам между указанными начальными и конечными токенами

, например:

dont capture{START}capture me 1{END}dont capture{END}dont capture{START}dont capture{START}capture me 2{END}dont capture 

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

поэтому в приведенном выше примере я хочу только матч:

  1. захватить меня 1
  2. захватить меня 2
+3

Вы пробовали что-нибудь? –

+0

И какое регулярное выражение у вас есть? – Jerry

+2

Полезный намек, посмотрите на поведение '?' – jozefg

ответ

3

Это не простая задача *, но достаточно легко сделать с помощью negative lookahead assertion:

regex = re.compile(r""" 
    \{START\} # Match {START} 
    (   # Match and capture the following: 
    (?:  # Start of non-capturing group, used to match a single character 
     (?!  # only if it's impossible to match the following: 
     \{  # - a literal { 
     (?:  # Inner non-capturing group, used for the following alternation: 
     START # - Either match the word START 
     |  # or 
     END # - the word END 
     )  # End of inner non-capturing group 
     \}  # - a literal } 
    )  # End of negative lookahead assertion 
     .  # Match any single character 
    )*  # Repeat as often as possible 
    )   # End of capturing group 1 
    \{END\} # until {END} is matched.""", 
    re.VERBOSE) 

Результат:

>>> regex.findall("dont capture{START}capture me 1{END}dont capture{END}dont capture{START}dont capture{START}capture me 2{END}dont capture") 
['capture me 1', 'capture me 2'] 

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

  • Это соответствует (но не фиксирует) {START}.
  • Затем он сопоставляет (и захватывает) один символ за другим, проверяя на каждом символе, что это не первый символ строки (под) {START} или {END}. Это гарантирует, что эти строки никогда не могут быть частью этой части матча.
  • Окончательно соответствует (но не фиксируется) {END}.

* особенно не \{START\}(.*?)\{END\} потому, что бы захватить {START}dont capture{START}capture me 2{END} в примере строки.

+0

Я предполагаю, что это тоже будет включать '{START}' и '{END}' в результате. –

+0

Возможно, обход вокруг может помочь. –

0

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

import re 

text = 'dont capture{START}capture me 1{END}dont capture{END}dont capture{START}dont capture{START}capture me 2{END}dont capture' 
pattern = r'{START}([^{]*){END}' 
print(re.findall(pattern, text)) # prints ['capture me 1', 'capture me 2'] 
+0

{} были использованы для примера. в реальном случае нет специальных разделителей тегов для использования – eyaler

+0

@eyaler: Ах, тогда ваша проблема отличается от того, о чем вы просили, и немного сложнее. Я думаю, что слегка модифицированная версия ответа TimPietzcker может работать в этом случае (делая отрицательные образы для двух разделителей). – Blckknght

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