Lex半复杂的正则表达式

时间:2018-03-04 02:23:38

标签: regex lex

所以,我正在为一所学校的项目工作,我们必须做一个壳,直到现在我一直很好。我需要弄清楚如何扩展我的正则表达式" words"以便识别特殊字符。

基本上,我需要能够通过某些特殊字符来分隔单词,但如果它们被转义则不能。

例如:echo sometext>file.txt将被标记为WORD WORD GREAT WORD。但是,echo sometext\>file.txt会被标记为WORD WORD,其中" sometext> file.txt"是一个字。

我无法找出可以处理此问题的正则表达式。这是我目前所拥有的: [^ \t\n][^ \t\n<>&|]*。这适用于挑选echo sometext>file.txt之类的内容,但我不确定如何扩展它以查找除空格或特殊字符之外的任何字符,除非该特殊字符被转义。

感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

怎么样:

(?:\\.|[^ \t\n<>&|])*

这&#34;打破了字#34;在\t\n<>&|上(即{{1} }}),除非转义。

演示:https://regex101.com/r/lEkNRk/1

或者:

[^ \t\n<>&|]

这也单独匹配(?:\\.|[^ \t\n<>&|])+|[ \t\n<>&|] 等等,如果没有转义。也许它更适合您建议的>模式。

演示:https://regex101.com/r/rkh8lC/1

答案 1 :(得分:1)

如果你正在使用(f)lex,你可能会想要这样的东西。它基于Posix 2016中的语法摘要,为了好玩而引入了几个基本原理,我尝试使用与该文档相同的令牌名称。

这里省略了许多重要的功能:

  • 正确处理报价需要做更多工作。我甚至都没试过。 (最令人讨厌的部分是,您可以在引用的字符串中包含命令扩展$(...),这是一个独立的词汇上下文。)

  • 我没有包含将yytext的副本保存到yylval的代码,这需要针对WORD以及保留字进行(但是不是元字符或以元字符开头的符号)因为保留字并不总是保留。这个事实也会在语法中产生一些问题。

  • 我没有区分NAMEWORD(规则5和8)。

  • 我没有费心去识别IO_NUMBER,尽管使用(f)lex的尾随上下文运算符非常简单。 (如果紧随该号码后面的字符为<>,则号码才有用。

  • 我也没有尝试识别ASSIGNMENT_WORD(见2.10.1)。赋值在语法上并不重要,但它们在语义上很重要,在识别这些单词时设置标志很有用。可以在ASSIGNMENT_WORD模式之前添加用于识别yylval并在WORD中设置标记的模式(请参阅下面有关排序模式的说明)。

下面列出了这些模式的顺序。当多个模式匹配相同的标记时,(f)lex具有定义的匹配顺序这一事实通常大大简化了正则表达式的构造,但这也意味着在某些情况下必须仔细地对规则进行排序。

[|&;()<>\n]   return *yytext;   /* Metacharacters, including newline */
[[:space:]]   ;                 /* Ignore other whitespace */
"||"          return OR_IF;     /* Multi-metacharacter sequences */
"&&"          return AND_IF;
";;"          return DSEMI;
"<<"          return DLESS;
"<<-"         return DLESSDASH;
"<<<"         return TLESS;     /* Bash here strings */
">>"          return DGREAT;
"<&"          return LESSAND;
">&"          return GREATAND;
"<>"          return LESSGREAT;
">|"          return CLOBBER;

"(("          return DLparen;   /* Bash arithmetic conditional */
"))"          return DRparen;

"if"          return If;        /* reserved words, only matched when   */
"then"        return Then;      /* they are a complete word (and often */
"else"        return Else;      /* treated as regular words even then).*/
"elif"        return Elif;
"fi"          return Fi;
"do"          return Do;
"done"        return Done;
"case"        return Case;
"esac"        return Esac;
"while"       return While;
"until"       return Until;
"for"         return For;
"in"          return In;
"time"        return Time;      /* In bash, this is reserved */

"{"           return Rbrace;
"}"           return Lbrace;
"!"           return Bang;

"[["          return DLbracket; /* Bash conditional */
"]]"          return DRbracket;

"#".*         ;                 /* Comments. Only if # would start a word. */

([^[:space:]|&;()<>]|\\.)+ return WORD;

这些模式集合经过精心设计,以便生成正确的令牌;模式不是相互排斥的。特别是:

  • 新行字符将匹配前两个规则。由于它实际上具有语法意义,因此忽略规则排在第二位。

  • 元字符永远不会是令牌的一部分(除非转义),因此WORD规则不允许它们。另一方面,{}!不是元字符,尽管它们在某些情况下具有语法意义;首先必须将它们识别为单词以便使用。从这个意义上说,它们类似于iffor等关键字;他们的模式需要在WORD规则之前,以便在它们形成完整的单词时正确识别它们。

  • 类似地,#字符仅在单词中的第一个字符时才开始注释。否则,它是一个普通的单词字符。同样,识别(并忽略)注释需要匹配规则在WORD之前。请注意,规则匹配终止评论的换行符;与任何其他换行符一样,换行符实际上具有语法重要性,因此必须将其返回给解析器。