Вот два важных факта о (f) лекс регулярных выражениях.(См. Руководство flex для полной документации шаблонов Flex. Этот раздел не очень длинный.)
In (f) lex, подстановочный знак .
соответствуетвсе что угодно кроме символа новой строки .Другими словами, это эквивалентно [^\n]
.Так что "<!".*
будет соответствовать только концу строки.Вы можете исправить это, используя вместо этого (.|\n)
, но см. Ниже.
(F) lex не обеспечивает жадного повторения (*?
).Все повторения распространяются на максимально возможное совпадение.Следовательно, (.*?)-->
будет соответствовать последнему -->
в строке, а (.|\n)*?-->
будет соответствовать последнему -->
в файле.
Возможнонапишите регулярное выражение, которое делает то, что вы хотите, хотя оно немного запутанно:
<!--([^-]|-[^-]|--+[^->])*--+>
должно работать, пока вводимый текст не заканчивается неоконченным комментарием.(Кавычки в вашем шаблоне не нужны, так как ни один из символов в кавычках не имеет какого-либо особого значения для (f) lex, но они не причиняют вреда. Я их пропустил, потому что не думаю, что они способствуют тому, чтобы шаблон стал менее читабельным.)
Повторяющаяся последовательность соответствует любому из:
- Символ, отличный от
-
;или - A
-
, за которым следует что-то отличное от -
;или - Два или более
-
, за которыми следует что-то отличное от >
.
Последняя альтернатива в повторении может потребовать некоторого объяснения.Основная проблема заключается в том, чтобы избежать проблем с такими входными данными, как
<!-- Comment with two many dashes --->
Если бы мы просто записали заманчивый --[^>]
в качестве третьей альтернативы, --->
не был бы распознан как завершение шаблона, так как ---
будет соответствовать --[^>]
(тире - это не правая угловая скобка), а >
будет соответствовать [^-]
, и сканирование будет продолжено.Добавление +
для соответствия более длинной последовательности тире недостаточно, потому что, как и многие механизмы регулярных выражений, (f) lex ищет самое длинное общее совпадение, а не самое длинное совпадение в каждом наборе альтернатив.Поэтому нам нужно написать --+[^->]
, что не может соответствовать ---
.
Если это было непонятно - и я понимаю, почему это не так - вместо этого вы можете использовать начальное условие , чтобы написать гораздо более простой набор шаблонов:
%x COMMENT
%%
"<!--" { BEGIN(COMMENT); }
<COMMENT>{
"-->" { BEGIN(INITIAL); }
[^-]+ ;
.|\n ;
}
Второе правило <COMMENT>
- это просто взлом эффективности;он избегает запуска неактивных действий для каждого персонажа.Со вторым правилом последнее правило действительно может соответствовать только одному -
, так что оно могло бы быть написано таким образом.Но полное его написание позволяет вам удалить второе правило и продемонстрировать себе, что оно работает без него.
Ключевым моментом для сопоставления комментария по частям, подобным этому, является то, что (f) lex всегда выбирает самое длинное совпадение, что в некоторой степени похоже на цель не жадных матчей.Находясь в начальном условии <COMMENT>
, -
будет соответствовать правилу возврата только одного символа, если оно не может быть частью совпадения -->
, которое длиннее.