2015-03-19 3 views
0

Я пишу компилятор. Я только начинаю, поэтому создаю сканер (или Lexer). В настоящее время я пишу некоторые регулярные определения, которые будут обработаны моим сканером. Попытка создать одну из них, я бег в следующей проблеме:Регулярное выражение - странное поведение

я тестирование, в RegExr, следующее (невероятно простой) регулярное выражение:

r = /(a|ab)/ 

Где «г» является регулярным определением; Я имею в виду, что регулярное выражение просто (a|ab).

Я думал, что язык L (г) будет (согласно книге Compilers: Principles, Techniques and Tools):

L(r) = {a, ab} 

Удивительно, но инструмент соответствует {a}!

Так что мой вопрос: почему такое поведение?

+0

'' 'в regex - это генератор переменного тока, то есть ваше регулярное выражение будет соответствовать' a' _or_ 'ab'. Вы хотите, чтобы он соответствовал 'a' _followed by_' ab'? –

+0

Привет @JamesThorpe, на самом деле я не хочу «находить» регулярное выражение. То, что я ищу, - это понять странное поведение. –

ответ

2

регулярного выражения a|ab спичек «а» или «б» (очевидно), но некоторые инструменты/языки (например, Java) считают ввод в соответствие, когда всех входа соответствует регулярному выражению, в то время как другие (например, JavaScript) считают вход для соответствия, если совпадений ввода.

Ваш инструмент должен быть «некоторым», чтобы соответствовать «{a}».

+0

Знаете ли вы онлайн-инструмент, который ведет себя как инструменты Java regex? –

+0

@ LeonardoManrique no, но вы можете заставить его вести себя так, добавив '^' в начало и '$' до конца, например '^ a | ab $'. btw ваше регулярное выражение эквивалентно 'ab?' – Bohemian

+0

Вы ссылаетесь на лексем? Если это так, я не хочу сопоставлять лексему с шаблоном, я просто разрабатывал регулярные определения. Когда я попытался использовать этот инструмент, я столкнулся с «ошибкой», которую мы обсуждали. Если вы обращаетесь к самому регулярному выражению, это эквивалентно 'a'. –

1

Регулятор анализирует текст слева направо, а в случае генератора переменного тока (|) он будет нацелен на совпадение с первым кандидатом.

Если вы используете:

(ab|a) 

Это будет соответствовать обоим ab и a «с.

Дело в том, что как только матч будет найден, глобальный матчи начнет следующую попытку матча после в конце первого матча.

Вы можете легко убедиться, что соответствующий язык равен {a,ab}: используйте регулярное выражение ^c(a|ab)d и используйте cabd. В этом случае у регулярного выражения нет выбора, кроме как выбрать второй вариант.

Скажем, регулярное выражение: (a|ab) и текст ab. Он будет соответствовать a, затем он начнется после a, поэтому он попытается сопоставить с b, но не получится.

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

Теперь, если вы введете (a|ba) в качестве регулярного выражения, оно будет соответствовать ранее ba ранее. Зачем? Потому что он также стремится найти первую попытку. И в тексте cbad, начинающийся с индекса 1 (b), считается лучше, чем начинающийся с индекса 2 (a).

+0

Привет CommuSoft. Да, вы правы, но если я напишу это регулярное выражение: (a | ba), инструмент будет соответствовать {a, ba}. –

+0

@ LeonardoManrique: хорошо, что он соответствует buth. Если вы будете использовать '^ (a | ab) $' и совпадение с 'ab', оно будет соответствовать. –

+1

@ LeonardoManrique: извините, что ваш комментарий неверен, см. Измененный ответ. –

0

По словам @bohemian некоторых регулярных выражений оценить только часть строки, если вы хотите, чтобы соответствовать всей строке, которую вы можете использовать регулярное выражение как это:

/^(a|ab)$/ 

Что только будет принимать или ab