Вот минимальный гибкий лексер C++ для этой проблемы. Ключом к нежадному сопоставлению являются начальные условия, как указано в руководстве по гибкости и в других местах.
Начальное условие — это просто еще одно состояние лексера. Когда требуется нежадное сопоставление, существует некоторый шаблон, который должен завершить сопоставление при его первом появлении.
В общем, независимо от состояния, если вы ищете целевую строку или шаблон, вам просто нужно убедиться, что нет других более общих шаблонов, которые могли бы соответствовать более длинному фрагменту ввода, содержащему целевой шаблон.
Начальные условия помогают, когда целевой шаблон является условным и его необходимо включить после некоторого более раннего совпадения. Вы включаете начальное условие, чтобы включить сопоставление с целевым шаблоном, и отключаете его, сбрасывая состояние на 0 или INITIAL
— или переключаясь в другое состояние для еще более условного сопоставления.
Состояния переключаются с помощью BEGIN
— также есть стек состояний для использования через yy_push_state
и yy_pop_state
.
В руководстве по flex есть много примеров условий запуска.
Вот гибкие правила, которые показывают нежадное сопоставление с гибкими стартовыми условиями - лексер сопоставляет первое вхождение собаки в строке до первого вхождения кошки - сопоставление нечувствительно к регистру.
Полный файл размещен в конце - для людей, незнакомых с flex, обратите внимание, что многие строки начинаются с пробела - это не случайно и требуется flex
%%
/* flex rules section */
string match;
dog {
// found a dog, change state to HAVE_DOG to start looking for a cat
BEGIN(HAVE_DOG);
// save the found dog
match = yytext;
}
/* save and keep going till cat is found */
<HAVE_DOG>. match += yytext;
<HAVE_DOG>cat {
// save the found cat
match += yytext;
// output the matched dog and cat
cout << match << "\n";
// ignore rest of line
BEGIN(SKIP_LINE);
}
/* no cat on this line, reset state */
<HAVE_DOG>\n BEGIN(0);
/* rules to ignore rest of the line then reset state */
<SKIP_LINE>{
.*
\n BEGIN(0);
}
/* nothing to do yet */
.|\n
Вот некоторые тестовые данные
$ cat dogcat.in.txt
Dog Ca Cat Cc Cat
dog Ca cat Cc cat
dOg Ca cAt Cc cAt
DOG CA CAT CC CAT
cat dog dog cat cat
dog kitten cat dog cat
dig cat dog can dog cut
dig dug dog cow cat cat
doc dogcat catdog
dog dog dog
cat cat cat
Построить с
flex -o dogcat.flex.cpp dogcat.flex.l && g++ -o dogcat dogcat.flex.cpp
Бежать с
$ ./dogcat < dogcat.in.txt
Dog Ca Cat
dog Ca cat
dOg Ca cAt
DOG CA CAT
dog dog cat
dog kitten cat
dog cow cat
dogcat
Полный гибкий файл
/* dogcat.flex.l */
/*
Build with:
flex -o dogcat.flex.cpp dogcat.flex.l && g++ -o dogcat dogcat.flex.cpp
*/
/*
A minimal C++ flex lexer that shows nongreedy matching with flex
start conditions
matches the first occurrence of dog on a line till the first
occurrence of cat
matching is case insensitive
*/
/* C++ lexer using yyFlexLexer in FlexLexer.h */
%option c++
/* case-insensitive patterns */
%option case-insensitive
/* generate main function for executable */
%option main
/* all input must be matched, no echo by default */
%option nodefault
/* debug output with lexer.set_debug(1) */
%option debug
/* start condition means dog was matched */
%x HAVE_DOG
/* start condition means to ignore remaining line */
%x SKIP_LINE
%{
#include <string>
#include <iostream>
// C++ flex lexer class
// needed because header itself has no guard
#ifndef yyFlexLexerOnce
# include <FlexLexer.h>
#endif
using namespace std;
namespace {
// the C++ lexer class from flex
yyFlexLexer lexer;
// main generated by flex still calls free yylex function even for C++ lexer
int yylex() {
return lexer.yylex();
}
}
%}
%%
/* flex rules section */
string match;
dog {
// found a dog, change state to HAVE_DOG to start looking for a cat
BEGIN(HAVE_DOG);
// save the found dog
match = yytext;
}
/* save and keep going till cat is found */
<HAVE_DOG>. match += yytext;
<HAVE_DOG>cat {
// save the found cat
match += yytext;
// output the matched dog and cat
cout << match << "\n";
// ignore rest of line
BEGIN(SKIP_LINE);
}
/* no cat on this line, reset state */
<HAVE_DOG>\n BEGIN(0);
/* rules to ignore rest of the line then reset state */
<SKIP_LINE>{
.*
\n BEGIN(0);
}
/* nothing to do yet */
.|\n
person
Zartaj Majeed
schedule
16.06.2021