Lex 半复杂正则表达式
Lex semi-complex regex expression
所以,我正在为学校做一个项目,我们必须制作一个 shell,到目前为止我一直做得很好。我需要弄清楚如何扩展 "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
之类的东西,但我不确定如何扩展它以查找除空格或特殊字符以外的任何字符,除非该特殊字符被转义。
感谢任何帮助。
怎么样:
(?:\.|[^ \t\n<>&|])*
、\t
、\n
、<
、>
、&
和 [=18] 上的“断言” =](即 [^ \t\n<>&|]
中的内容),除非已转义。
演示:https://regex101.com/r/lEkNRk/1
或者:
(?:\.|[^ \t\n<>&|])+|[ \t\n<>&|]
这也单独匹配
、>
等等,如果没有转义。也许它更适合您建议的 WORD WORD GREAT WORD
模式。
如果您正在使用 (f)lex,您可能需要这样的东西。它基于 Posix 2016 中的语法摘要,为了好玩而加入了一些 bashisms,我尝试使用与该文档相同的标记名称。
这里省略了很多重要的功能:
正确处理报价需要做更多的工作。我什至没有尝试过。 (最烦人的部分是你可以在带引号的字符串中包含命令扩展 $(...)
,这是一个独立的词法上下文。)
我没有包含将 yytext
的副本保存到 yylval
的代码,这需要为 WORD
和保留字(但不是元字符或以元字符开头的符号),因为保留字并不总是保留的。这个事实也造成了一些语法问题。
我没有区分NAME
和WORD
(规则5和8)。
虽然用(f)lex 的trailing-context 算子straight-forward,但我懒得认IO_NUMBER
。 (仅当紧跟在数字后面的字符是 <
或 >
.
时,数字才是特殊的
我也没有尝试识别ASSIGNMENT_WORD
(见2.10.1)。赋值在句法上并不重要,但在语义上很重要,在识别此类词时设置标志很有用。可以在 WORD
模式之前添加识别 ASSIGNMENT_WORD
s 并在 yylval
中设置标志的模式(请参阅下面关于订购模式的注释)。
下面有关于这些模式排序的注释。当多个模式匹配同一个标记时,(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
规则不允许使用它们。另一方面,{
、}
和 !
不是元字符,尽管它们在某些上下文中具有语法意义;它们必须首先被识别为单词才能使用。从这个意义上讲,它们类似于 if
和 for
等关键字;它们的模式需要出现在 WORD
规则之前,以便在它们形成一个完整的单词时被正确识别。
类似地,#
字符仅当它是单词中的第一个字符时才开始注释。否则就是一个普通的字字符。同样,识别(和忽略)注释需要匹配规则出现在 WORD
之前。请注意,该规则 not 匹配终止注释的换行符;该换行符实际上在语法上很重要,就像任何其他换行符一样,因此必须将其返回给解析器。
所以,我正在为学校做一个项目,我们必须制作一个 shell,到目前为止我一直做得很好。我需要弄清楚如何扩展 "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
之类的东西,但我不确定如何扩展它以查找除空格或特殊字符以外的任何字符,除非该特殊字符被转义。
感谢任何帮助。
怎么样:
(?:\.|[^ \t\n<>&|])*
、\t
、\n
、<
、>
、&
和 [=18] 上的“断言” =](即 [^ \t\n<>&|]
中的内容),除非已转义。
演示:https://regex101.com/r/lEkNRk/1
或者:
(?:\.|[^ \t\n<>&|])+|[ \t\n<>&|]
这也单独匹配
、>
等等,如果没有转义。也许它更适合您建议的 WORD WORD GREAT WORD
模式。
如果您正在使用 (f)lex,您可能需要这样的东西。它基于 Posix 2016 中的语法摘要,为了好玩而加入了一些 bashisms,我尝试使用与该文档相同的标记名称。
这里省略了很多重要的功能:
正确处理报价需要做更多的工作。我什至没有尝试过。 (最烦人的部分是你可以在带引号的字符串中包含命令扩展
$(...)
,这是一个独立的词法上下文。)我没有包含将
yytext
的副本保存到yylval
的代码,这需要为WORD
和保留字(但不是元字符或以元字符开头的符号),因为保留字并不总是保留的。这个事实也造成了一些语法问题。我没有区分
NAME
和WORD
(规则5和8)。虽然用(f)lex 的trailing-context 算子straight-forward,但我懒得认
IO_NUMBER
。 (仅当紧跟在数字后面的字符是<
或>
. 时,数字才是特殊的
我也没有尝试识别
ASSIGNMENT_WORD
(见2.10.1)。赋值在句法上并不重要,但在语义上很重要,在识别此类词时设置标志很有用。可以在WORD
模式之前添加识别ASSIGNMENT_WORD
s 并在yylval
中设置标志的模式(请参阅下面关于订购模式的注释)。
下面有关于这些模式排序的注释。当多个模式匹配同一个标记时,(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
规则不允许使用它们。另一方面,{
、}
和!
不是元字符,尽管它们在某些上下文中具有语法意义;它们必须首先被识别为单词才能使用。从这个意义上讲,它们类似于if
和for
等关键字;它们的模式需要出现在WORD
规则之前,以便在它们形成一个完整的单词时被正确识别。类似地,
#
字符仅当它是单词中的第一个字符时才开始注释。否则就是一个普通的字字符。同样,识别(和忽略)注释需要匹配规则出现在WORD
之前。请注意,该规则 not 匹配终止注释的换行符;该换行符实际上在语法上很重要,就像任何其他换行符一样,因此必须将其返回给解析器。