2010-01-12 7 views
5

Я читаю книгу, и они приводят пример того, как соответствовать заданной строке с регулярными выражениями. Вот их пример:Стандартное выражение Regex vs python regex

b*(abb*)*(a|∊) - Strings of a's and b's with no consecutive a's. 

Теперь я попытался преобразовать его в Python, как так:

>> p = re.compile(r'b*(abb*)*(a|)') # OR 
>> p = re.compile(r'b*(abb*)*(a|\b)') 

# BUT it still doesn't work 
>>> p.match('aa') 
<_sre.SRE_Match object at 0x7fd9ad028c68> 

Мой вопрос два раза:

  1. Что является эквивалентом epsilon в python, чтобы сделать вышеприведенный пример?
  2. Может кто-нибудь объяснить мне, почему теоретический или стандартный способ делать регулярные выражения не работает в python? Может ли это иметь какое-то отношение к самому длинному и кратчайшему совпадению?

Разъяснение: Для людей, спрашивающих, что стандартное регулярное выражение - это формальная стандартная теория языка: http://en.wikipedia.org/wiki/Regular_expression#Formal_language_theory

+1

комментарий на примере ошибочен ... регулярное выражение не только матч струн-х и б без последовательных в. Я бы заменил bb * на b + btw. –

+1

Каково ожидаемое поведение эпсилона в этом контексте? Я никогда не видел этого раньше, и я программировал 12 лет ... – jathanism

+2

«Стандартное» регулярное выражение? Кто определил стандарт? ANSI? ISO? IEEE? О, МОЙ БОГ? –

ответ

5

Спасибо за ответы. Я чувствую, что каждый ответ был частью ответа. Вот что я искал.

  1. ? Символ - это только сокращение для (что-то | & epsilon;). Таким образом, (a | & epsilon;) можно переписать как a?. Таким образом, пример становится:

    b*(abb*)*a? 
    

    В питона мы бы написать:

    p = re.compile(r'^b*(abb*)*a?$') 
    
  2. Причина прямой перевод регулярного синтаксиса регулярных выражений в Python (т.е. копировать и вставить) не работает потому, что питона спичек кратчайшая подстрока (если символы $ или^отсутствуют), а теоретические регулярные выражения соответствуют самой длинной начальной подстроке.
    Так, например, если у нас была строка:

    s = 'aa' 
    

    Наш учебник регулярных выражений б * (АВВ *) * а? не соответствовал бы ему, потому что он имеет два а. Однако, если мы копируем его прямо в питон:

    >> p = re.compile(r'b*(abb*)*a?') 
    >> bool(p.match(s)) 
    True 
    

    Это потому, что наше регулярное выражение соответствует только подстроке «а» нашей строки «аа».
    Для того, чтобы сказать питона сделать матч на всю строку, мы должны сказать ему, где начало и конец струны, с ^ и $ символов соответственно:

    >> p = re.compile(r'^b*(abb*)*a?$') 
    >> bool(p.match(s)) 
    False 
    

    Обратите внимание, что python regex match() соответствует , начинающему строки, поэтому он автоматически принимает ^ в начале. Однако функция search() нет, и поэтому мы сохраняем ^.
    Так, например:

    >> s = 'aa' 
    >> p = re.compile(r'b*(abb*)*a?$') 
    >> bool(p.match(s)) 
    False     # Correct 
    >> bool(p.search(s)) 
    True     # Incorrect - search ignored the first 'a' 
    
+0

Отличный подведение итогов ответов! –

+0

«... python соответствует самой короткой подстроке ...» неверно. Это просто не обязательно соответствует самой длинной подстроке, как математически правильное регулярное выражение. –

+0

@Alan: Он соответствует самой короткой подстроке, если нет или нет. – drozzy

3
  • Используйте bool(p.match('aa')), чтобы проверить, если регулярное выражение спичек или не

  • p = re.compile('b*(abb*)*a?$')

  • \b соответствует границе строки; место между \w и \W (символами слов и символов без слов)

Regexp вполне стандартна в питона. Тем не менее, каждый язык имеет некоторый вкус, они не на 100% переносимы. Существуют незначительные отличия, которые вы ожидаете найти до использования regexp на любом конкретном языке.

Добавление

\epsilon не имеет специальный символ в питона. Это пустой набор символов.

В вашем примере a|\epsilon эквивалентен (a|) или только a?. После чего $ обязателен для соответствия концу строки.

+0

Я не думаю, что OP хочет границу слова ... вы можете использовать epsilon посреди слова ... это просто означает пустую строку ... Кроме того, по стандарту Я думаю, что OP означает вроде регулярных выражений, используемых в теории вычислительных учебников ... без. или^$ или \ w или [1-9] или {3}, но с \ epsilon, \ lambda и т. д. –

+0

Я не уверен, что вы подразумеваете под «Вот почему в книгах они придумывают специальные символы, которые вы ожидаете для поиска до использования на любом конкретном языке ». Просьба уточнить/переписать, и я соглашусь. – drozzy

+0

Это была быстрая догадка. Прошло много времени с тех пор, как я изучил теоретическое регулярное выражение. Удалены. Забудьте об этом :) –

3

Я не совсем уверен, как работает совпадение в python, но я думаю, вам может понадобиться добавить^.... $ в ваш RE. Соответствие RegExp обычно соответствует подстрокам, и оно находит наибольшее совпадение, в случае p.match ('aa'), который является «a» (возможно, первым).^... $ гарантирует, что вы соответствуете строке ENTIRE, и я считаю, что вы хотите.

Теоретический/стандартный reg exps предполагает, что вы всегда соответствуете всей строке, потому что вы используете ее для определения языка строк, которые соответствуют, а не для поиска подстроки во входной строке.

+0

^здесь не нужно. Предполагается, что в re.match. В re.search это не единственная разница между этими двумя. –

+0

интересный нужен? потому что если это не вы, то regexp должен быть ... (a $ | $), в противном случае это соответствует чему-либо с a в нем ... –

+0

'$' представляет конец строки, я не думаю, что это что вы ищете. 're.match' делает это уже как с'^'(для начала строки). – jathanism

1

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

re.compile(r'^(a(?!a)|b)*$') 
5

На самом деле, пример работает просто отлично ... до мелких деталей. Я бы написал:

>>> p = re.compile('b*(abb*)*a?') 
>>> m = p.match('aa') 
>>> print m.group(0) 
'a' 
>>> m = p.match('abbabbabababbabbbbbaaaaa') 
>>> print m.group(0) 
abbabbabababbabbbbba 

Обратите внимание, что группа 0 возвращает часть строки, соответствующую регулярному выражению.

Как вы можете видеть, выражение соответствует последовательности a и b без повторения a. Если на самом деле, вы хотите проверить всю строку, вам нужно немного изменилось:

>>> p = re.compile('^b*(abb*)*a?$') 
>>> m = p.match('aa') 
>>> print m 
None 

признание силы в ^ и $ начала и конца строки.

В конце концов, вы можете комбинировать оба метода с использованием первого регулярного выражения, но тестирование в конце:

>>> len(m.group(0)) == len('aa') 

Добавлено: Для второй части ВЗ, мне кажется, есть не существует расхождения между стандартным регулярным выражением и реализацией python. Конечно, нотация немного отличается, и реализация python предлагает некоторые расширения (как и большинство других пакетов).

+0

+1 за избиение меня до ответа! :) btw '^' не является обязательным, потому что re.match() только пытается создать шаблон в самом начале строки. –

+0

oh .. ваш пример неправильный. 'p = re.compile ('b * (abb) * a?')' не соответствует 'aba' –

+0

oops .. просто забыли звезду в первом регулярном выражении ... исправлено! – PierreBdR

1

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

Для чего это стоит, ваш шаблон соответствует 'a'. То есть, это соответствие:

  • ноль или более «b„ы (выбор ноль)
  • ноль или более“(abb*)„ы (выбор ноль)
  • один“a» или слово, заканчивающееся (выбор a).

Как Джонатан Фейнберг отметил, если вы хотите, чтобы вся строка матчей, вы должны закрепить начало ('^') и конец ('$') вашего регулярного выражения. Вы также должны использовать необработанную строку при построении регулярных выражений в python: r'my regex '. Это предотвратит чрезмерную обратную косую черту, которая ускользает от путаницы.

1

проблема с выражением является то, что он совпадает с пустой строкой, а это означает, что если вы делаете:

>>> p = re.compile('b*(abb*)*(a|)') 
>>> p.match('c').group(0) 
'' 

и так re.match пытается соответствовать начало строки, вы должны сказать ему сопоставьте его до конца строки. просто использовать $ для этого

>>> p = re.compile(r'b*(abb*)*(a|)$') 
>>> print p.match('c') 
None 
>>> p.match('ababababab').group(0) 
'ababababab' 

ps- вы можете отметить, что я использовал r'pattern»вместо„шаблон“больше на этом here (первые пункты)