如何为 flex 生成至少一次所有元音的字符串的正则表达式?

How to generate regular expression for string having all vowels at least once for flex?

您可能认为这是 this 的重复问题。

实际上它是那个问题的类似问题。那我为什么还要问呢?

因为,该问题的公认答案无效。答案可能满足 OP 的要求,但这不是一般答案。

另一个原因是,它应该在 flex 中工作。

我需要一个正则表达式,它只接受那些以任何顺序包含元音的字符串。

它可能有一些其他字母,但所有元音必须至少出现一次。

让我们看一些例子:

String                         Accepted or Not
----------------------         ---------------
abceioussa                     Accepted
aeiou                          Accepted
uioae                          Accepted
odsidsfusjldkfuuuu             Not Accepted
bcesdddsoaiaaau                Accepted
aaaaaaaaeeeeeeeooooiu          Accepted
aasssssaeeeeeeeoeoooi          Not Accepted

编辑:

记住,它应该在 flex 中工作。

编辑 2:

任务:

Pattern                                                         Action
-------------------------------------------------------------   --------------------
Blank Space, tab space                                          Do nothing
New line                                                        Count number of line
Any word contains all five vowels at least once                 Print VOWELS
Any word ends with s or es                                      Print PLURAL
Any word ends with ly                                           Print ADVERB
Any word ends with ing                                          Print CONTINUOUS
is/do/go/be/are/was/were/did                                    Print VERB
a/an/the                                                        Print ARTICLE
Any word starts with uppercase letter and none of the above     Print NOUN
Anything else                                                   Print NOT_RECOGNIZED

Scanner4.l:

只需要为正则定义填写表达式vowel

%{
    /* comments */
    #define ECHO fwrite(yytext, yyleng,1,yyout);
    int yylineno = 0, ii;
%}
letter [a-zA-Z]
uppercase [A-Z]
digit [0-9]
digits [0-9]+
punc [-=\+\_\.,\.\|\~\!$\%\^\&\(\;\'\"\?\{\}\[\]\)\/\#\*@]
anything ({letter}|{digit})
spacetab [\t ]+
endmark [\n\t ]
dot [\.]
hp [\-]
verb (is|do|go|be|are|was|were|did)
article (a|an|the)
normal ({anything}|{punc})
vowel //here you have to write the expression
%option noyywrap
%%
{spacetab}|{punc}   { 
                        fprintf(yyout,"%s", yytext);
                        printf(":%s:%d ECHO\n",yytext,yylineno);
                        /* do nothing */
                    }
\n  {
        yylineno++; 
        ECHO; 
        printf(":%s:%d no echo\n",yytext,yylineno);
    }
{vowel}{endmark}    {
                        fprintf(yyout," VOWELS ");
                        fprintf(yyout,"%c", yytext[yyleng-1]);
                        if(yytext[yyleng-1]=='\n') yylineno++;
                        printf(":%s:%d vowels\n",yytext,yylineno);
                    }
{verb}{endmark}     {
                        fprintf(yyout," VERB ");
                        fprintf(yyout,"%c", yytext[yyleng-1]);
                        if(yytext[yyleng-1]=='\n') yylineno++;
                        printf(":%s:%d verb\n",yytext,yylineno);
                    }
{article}{endmark}  {
                        fprintf(yyout," ARTICLE ");
                        fprintf(yyout,"%c", yytext[yyleng-1]);
                        if(yytext[yyleng-1]=='\n') yylineno++;
                        printf(":%s:%d article\n",yytext,yylineno);
                    }
{letter}*(s|es){endmark}    {
                            fprintf(yyout," PLURAL ");
                            fprintf(yyout,"%c", yytext[yyleng-1]);
                            if(yytext[yyleng-1]=='\n') yylineno++;
                            printf(":%s:%d plural\n",yytext,yylineno);
                        }
{letter}*(ly){endmark}  {
                            fprintf(yyout," ADVERB ");
                            fprintf(yyout,"%c", yytext[yyleng-1]);
                            if(yytext[yyleng-1]=='\n') yylineno++;
                            printf(":%s:%d adverb\n",yytext,yylineno);
                        }
{letter}*(ing){endmark}     {
                            fprintf(yyout," CONTINUOUS ");
                            fprintf(yyout,"%c", yytext[yyleng-1]);
                            if(yytext[yyleng-1]=='\n') yylineno++;
                            printf(":%s:%d continuous\n",yytext,yylineno);
                        }
{uppercase}{letter}*{endmark}   {
                        fprintf(yyout," NOUN ");
                        fprintf(yyout,"%c", yytext[yyleng-1]);
                        if(yytext[yyleng-1]=='\n') yylineno++;
                        printf(":%s:%d noun\n",yytext,yylineno);
                    }

{normal}+{endmark}  { 
                        fprintf(yyout," NOT_RECOGNIZED%c", yytext[yyleng-1]);
                        if(yytext[yyleng-1]=='\n') yylineno++;
                        printf(":%s:%d as it is\n",yytext,yylineno);
                    }
%%
int main(){
    yyin = fopen("Input4.txt","r");
    yyout = fopen("Output4.txt","w");
    yylex();
    fprintf(yyout, "# of lines = %d\n", yylineno);
    fclose(yyin);
    fclose(yyout);
    return 0;
}

Input4.txt:

aasdfeasdfiasoasdfuasd aeiogedaeido aeiou oeiua aeeeee aeiouuu
speaiously Addoiuea aaaaaaa ing ly

预计Output4.txt:

VOWELS  NOT_RECOGNIZED  VOWELS  VOWELS  NOT_RECOGNIZED  VOWELS
     VOWELS   VOWELS   NOT_RECOGNIZED  CONTINUOUS  ly
# of lines = 1

我通过以下命令编译它:

flex Scanner4.l
mingw32-gcc -c lex.yy.c -o Scanner4.yy.o
mingw32-g++ -o Scanner4.yy.exe Scanner4.yy.o
Scanner4.yy

这个基于积极前瞻的正则表达式应该适合你:

\b(?=[[:alpha:]]*[Aa])(?=[[:alpha:]]*[Ee])(?=[[:alpha:]]*[Ii])(?=[[:alpha:]]*[Oo])(?=[[:alpha:]]*[Uu])[[:alpha:]]+\b

RegEx Demo

(?=\w*a) 强制在单词中出现 a 等或其他前瞻强制所有元音,即 a,e,i,o,u.

我要使用这个 class [aeiou] 包含英语元音的字符。

[^aeiou]*[aeiou]+...

像上面那样的东西可以工作,但你说它必须包含所有的元音,没有特定的顺序。所以要捕捉这个意图,你需要这样的东西。

[^aeiou]*(a[^eiou]*|e[^aiou]*|i[^aeou]*|o[^aeiu]*|u[^aeio]*)...

现在你明白了吗?我们必须提供很多更改,我们必须将它们嵌套,以表明我们正在寻找迄今为止我们尚未匹配的内容。

我们的想法是 条件 每次更改,然后继续进行,就好像我们可以假设我们不再寻找刚刚匹配的内容一样。没有技巧,只是很多正则表达式。

但是,您需要 (n-1)(n-2)(n-3)... 条款。有 5 个元音它可以工作,但它很好......不理想。

只是为了说明这件事的荒谬性。这是完整的正则表达式。不,我不是手写的,我写了一个小程序来生成它。

[^aeiou]*(a[^eiou]*(e[^iou]*(i[^ou]*(o[^u]*(u)|u[^o]*(o))|o[^iu]*(i[^u]*(u)|u[^i]*(i))|u[^io]*(i[^o]*(o)|o[^i]*(i)))|i[^eou]*(e[^ou]*(o[^u]*(u)|u[^o]*(o))|o[^eu]*(e[^u]*(u)|u[^e]*(e))|u[^eo]*(e[^o]*(o)|o[^e]*(e)))|o[^eiu]*(e[^iu]*(i[^u]*(u)|u[^i]*(i))|i[^eu]*(e[^u]*(u)|u[^e]*(e))|u[^ei]*(e[^i]*(i)|i[^e]*(e)))|u[^eio]*(e[^io]*(i[^o]*(o)|o[^i]*(i))|i[^eo]*(e[^o]*(o)|o[^e]*(e))|o[^ei]*(e[^i]*(i)|i[^e]*(e))))|e[^aiou]*(a[^iou]*(i[^ou]*(o[^u]*(u)|u[^o]*(o))|o[^iu]*(i[^u]*(u)|u[^i]*(i))|u[^io]*(i[^o]*(o)|o[^i]*(i)))|i[^aou]*(a[^ou]*(o[^u]*(u)|u[^o]*(o))|o[^au]*(a[^u]*(u)|u[^a]*(a))|u[^ao]*(a[^o]*(o)|o[^a]*(a)))|o[^aiu]*(a[^iu]*(i[^u]*(u)|u[^i]*(i))|i[^au]*(a[^u]*(u)|u[^a]*(a))|u[^ai]*(a[^i]*(i)|i[^a]*(a)))|u[^aio]*(a[^io]*(i[^o]*(o)|o[^i]*(i))|i[^ao]*(a[^o]*(o)|o[^a]*(a))|o[^ai]*(a[^i]*(i)|i[^a]*(a))))|i[^aeou]*(a[^eou]*(e[^ou]*(o[^u]*(u)|u[^o]*(o))|o[^eu]*(e[^u]*(u)|u[^e]*(e))|u[^eo]*(e[^o]*(o)|o[^e]*(e)))|e[^aou]*(a[^ou]*(o[^u]*(u)|u[^o]*(o))|o[^au]*(a[^u]*(u)|u[^a]*(a))|u[^ao]*(a[^o]*(o)|o[^a]*(a)))|o[^aeu]*(a[^eu]*(e[^u]*(u)|u[^e]*(e))|e[^au]*(a[^u]*(u)|u[^a]*(a))|u[^ae]*(a[^e]*(e)|e[^a]*(a)))|u[^aeo]*(a[^eo]*(e[^o]*(o)|o[^e]*(e))|e[^ao]*(a[^o]*(o)|o[^a]*(a))|o[^ae]*(a[^e]*(e)|e[^a]*(a))))|o[^aeiu]*(a[^eiu]*(e[^iu]*(i[^u]*(u)|u[^i]*(i))|i[^eu]*(e[^u]*(u)|u[^e]*(e))|u[^ei]*(e[^i]*(i)|i[^e]*(e)))|e[^aiu]*(a[^iu]*(i[^u]*(u)|u[^i]*(i))|i[^au]*(a[^u]*(u)|u[^a]*(a))|u[^ai]*(a[^i]*(i)|i[^a]*(a)))|i[^aeu]*(a[^eu]*(e[^u]*(u)|u[^e]*(e))|e[^au]*(a[^u]*(u)|u[^a]*(a))|u[^ae]*(a[^e]*(e)|e[^a]*(a)))|u[^aei]*(a[^ei]*(e[^i]*(i)|i[^e]*(e))|e[^ai]*(a[^i]*(i)|i[^a]*(a))|i[^ae]*(a[^e]*(e)|e[^a]*(a))))|u[^aeio]*(a[^eio]*(e[^io]*(i[^o]*(o)|o[^i]*(i))|i[^eo]*(e[^o]*(o)|o[^e]*(e))|o[^ei]*(e[^i]*(i)|i[^e]*(e)))|e[^aio]*(a[^io]*(i[^o]*(o)|o[^i]*(i))|i[^ao]*(a[^o]*(o)|o[^a]*(a))|o[^ai]*(a[^i]*(i)|i[^a]*(a)))|i[^aeo]*(a[^eo]*(e[^o]*(o)|o[^e]*(e))|e[^ao]*(a[^o]*(o)|o[^a]*(a))|o[^ae]*(a[^e]*(e)|e[^a]*(a)))|o[^aei]*(a[^ei]*(e[^i]*(i)|i[^e]*(e))|e[^ai]*(a[^i]*(i)|i[^a]*(a))|i[^ae]*(a[^e]*(e)|e[^a]*(a)))))

生成上述正则表达式的代码:

static void Main(string[] args)
{
  var vowels = new HashSet<char>("aeiou".ToCharArray());
  var sb = new StringBuilder();
  BuildRegex(vowels, sb);
  Console.WriteLine(sb);
}

private static void BuildRegex(HashSet<char> vowels, StringBuilder sb)
{
  if (vowels.Count == 0)
  {
    return;
  }
  sb.Append("[^" + string.Join(string.Empty, vowels) + "]*");
  if (vowels.Count > 0)
  {
    sb.Append('(');
    int i = 0;
    foreach (var vowel in vowels.OrderBy(x => x))
    {
      var vowels2 = new HashSet<char>(vowels);
      vowels2.Remove(vowel);
      if (i > 0)
      {
        sb.Append('|');
      }
      sb.Append(vowel);
      BuildRegex(vowels2, sb);
      i++;
    }
    sb.Append(')');
  }
}
static int array[5];


%%
[a-zA-Z]            {
                        int i = 0;
                        for (i = 0; i < 5' i++ {
                            array[i] = 0;
                        }
                        char a;
                        i = 0;
                        for (a = yytext[i]; a != '[=10=]'; i++) {
                            if (a == 'a') {
                                array[0] = 1;
                            }
                            if (a == 'e') {
                                array[1] = 1;
                            }
                            if (a == 'i') {
                                array[2] = 1;
                            }
                            if (a == 'o') {
                                array[3] = 1;
                            }
                            if (a == 'u') {
                                array[4] = 1;
                            }
                        }
                        if (array[0] == 1 && array[1] == 1 && array[2] == 1 && array[3] == 1 && array[4] == 1) {
                            printf("VOWELS\n");
                        }
                    }
%%

正则表达式:

a.*e.*i.*o.*u|a.*e.*i.*u.*o|a.*e.*o.*i.*u|a.*e.*o.*u.*i|a.*e.*u.*i.*o|a.*e.*u.*o.*i|a.*i.*e.*o.*u|a.*i.*e.*u.*o|a.*i.*o.*e.*u|a.*i.*o.*u.*e|a.*i.*u.*e.*o|a.*i.*u.*o.*e|a.*o.*e.*i.*u|a.*o.*e.*u.*i|a.*o.*i.*e.*u|a.*o.*i.*u.*e|a.*o.*u.*e.*i|a.*o.*u.*i.*e|a.*u.*e.*i.*o|a.*u.*e.*o.*i|a.*u.*i.*e.*o|a.*u.*i.*o.*e|a.*u.*o.*e.*i|a.*u.*o.*i.*e|e.*a.*i.*o.*u|e.*a.*i.*u.*o|e.*a.*o.*i.*u|e.*a.*o.*u.*i|e.*a.*u.*i.*o|e.*a.*u.*o.*i|e.*i.*a.*o.*u|e.*i.*a.*u.*o|e.*i.*o.*a.*u|e.*i.*o.*u.*a|e.*i.*u.*a.*o|e.*i.*u.*o.*a|e.*o.*a.*i.*u|e.*o.*a.*u.*i|e.*o.*i.*a.*u|e.*o.*i.*u.*a|e.*o.*u.*a.*i|e.*o.*u.*i.*a|e.*u.*a.*i.*o|e.*u.*a.*o.*i|e.*u.*i.*a.*o|e.*u.*i.*o.*a|e.*u.*o.*a.*i|e.*u.*o.*i.*a|i.*a.*e.*o.*u|i.*a.*e.*u.*o|i.*a.*o.*e.*u|i.*a.*o.*u.*e|i.*a.*u.*e.*o|i.*a.*u.*o.*e|i.*e.*a.*o.*u|i.*e.*a.*u.*o|i.*e.*o.*a.*u|i.*e.*o.*u.*a|i.*e.*u.*a.*o|i.*e.*u.*o.*a|i.*o.*a.*e.*u|i.*o.*a.*u.*e|i.*o.*e.*a.*u|i.*o.*e.*u.*a|i.*o.*u.*a.*e|i.*o.*u.*e.*a|i.*u.*a.*e.*o|i.*u.*a.*o.*e|i.*u.*e.*a.*o|i.*u.*e.*o.*a|i.*u.*o.*a.*e|i.*u.*o.*e.*a|o.*a.*e.*i.*u|o.*a.*e.*u.*i|o.*a.*i.*e.*u|o.*a.*i.*u.*e|o.*a.*u.*e.*i|o.*a.*u.*i.*e|o.*e.*a.*i.*u|o.*e.*a.*u.*i|o.*e.*i.*a.*u|o.*e.*i.*u.*a|o.*e.*u.*a.*i|o.*e.*u.*i.*a|o.*i.*a.*e.*u|o.*i.*a.*u.*e|o.*i.*e.*a.*u|o.*i.*e.*u.*a|o.*i.*u.*a.*e|o.*i.*u.*e.*a|o.*u.*a.*e.*i|o.*u.*a.*i.*e|o.*u.*e.*a.*i|o.*u.*e.*i.*a|o.*u.*i.*a.*e|o.*u.*i.*e.*a|u.*a.*e.*i.*o|u.*a.*e.*o.*i|u.*a.*i.*e.*o|u.*a.*i.*o.*e|u.*a.*o.*e.*i|u.*a.*o.*i.*e|u.*e.*a.*i.*o|u.*e.*a.*o.*i|u.*e.*i.*a.*o|u.*e.*i.*o.*a|u.*e.*o.*a.*i|u.*e.*o.*i.*a|u.*i.*a.*e.*o|u.*i.*a.*o.*e|u.*i.*e.*a.*o|u.*i.*e.*o.*a|u.*i.*o.*a.*e|u.*i.*o.*e.*a|u.*o.*a.*e.*i|u.*o.*a.*i.*e|u.*o.*e.*a.*i|u.*o.*e.*i.*a|u.*o.*i.*a.*e|u.*o.*i.*e.*a

只需将点替换为 [a-zA-Z]。

其实flex是做不到的。因为,我尝试了以下但没有成功。

  1. 起初,我尝试 运行 全部 5 个 flex 程序!组合,但它立即崩溃了!
  2. 那我运行 flex程序的缩减形式为5!组合了一个多小时,然后就给了fatal error!个信息!

所以,我得出结论,flex 是不可能的。