首页 > 解决方案 > 捕获包含 - 但不以破折号结尾的名称

问题描述

我正在尝试捕获可能包含破折号的名称(不以数字开头),例如hello-world. 我的问题是我也有与它冲突的单个破折号和符号的规则:

[A-Za-z][A-Za-z0-9-]+     { /* capture "hello-world" */ }
"-"                       { return '-'; }
">"                       { return '>'; }

当词法分析器读取hello-world->前面的规则时,会产生hello-world-and >,而我期望hello-world,->被单独捕获。为了解决它,我以这种方式修复了它:

[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9]+     { /* ensure final dash is never included at the end */ }

这行得通,除了单字母单词,所以最后我实现了这个:

[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9]+     { /* ensure final dash is never included at the end */ }
[A-Za-z][A-Za-z0-9]*                  { /* capture possible single letter words */ }

问题:有没有更优雅的方法来做到这一点?

标签: parsingflex-lexer

解决方案


[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9]+
[A-Za-z][A-Za-z0-9]*

请注意,正如您所说,第一条规则已经涵盖了不是单个字母的所有内容。所以第二条规则只需要匹配单个字母并且可以缩短为[A-Za-z]

[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9]+
[A-Za-z]

现在第二个规则只是第一个规则的前缀,所以我们可以通过使第一个字母后面的部分成为可选的部分来将其组合成一个规则:

[A-Za-z]([A-Za-z0-9-]*[A-Za-z0-9]+)?

最后+一位是不必要的,因为除了最后一个字符之外的所有内容都可以与中间部分匹配,所以最简单的版本是:

[A-Za-z]([A-Za-z0-9-]*[A-Za-z0-9])?

推荐阅读