我正在编写脚本语言的解析。
我需要识别strings
,integers
和floats
。
我使用规则成功识别字符串:
[a-zA-Z0-9_]+ {return STRING;}
但是我在识别Integers和Floats时遇到了问题。这些是我写的(错误的)规则:
["+"|"-"][1-9]{DIGIT}* { return INTEGER;}
["+"|"-"]["0." | [1-9]{DIGIT}*"."]{DIGIT}+ {return FLOAT;}
我该如何修复它们?
此外,由于“ abc123 ”是一个有效的字符串,我怎样才能确保它被识别为字符串而不是字符串的串联(“abc
” )和一个整数(“123
”)?
答案 0 :(得分:4)
第一个问题:(...)
和[...]
之间存在差异。你的正则表达式不符合你的想法,因为你使用了错误的标点符号。
除此之外:
没有数字规则可识别0
。
两个数字规则都需要明确的符号。
您的STRING规则会识别整数。
所以,开始:
[...]
包含单个字符或字符范围的集。它匹配单个字符,它是集合的成员。
(...)
包含正则表达式。括号用于分组,如数学中那样。
"..."
包含单个字符的序列,并且恰好与这些字符匹配。
考虑到这一点,让我们来看看
["+"|"-"][1-9]{DIGIT}*
第一个括号表达式["+"|"-"]
是一组单独的字符或范围。在这种情况下,该集合包含:“, + ,”(同样,由于集合包含零个或一个实例,因此无效每个成员), | ,以及范围“ - ”,这是一个端点是相同字符的范围,因此只包括字符,“,已经在集合中。简而言之,这相当于["+|]
。它将匹配这三个字符中的一个。它实际上需要这三个字符中的一个,实际上
第二个括号表达式[1-9]
匹配范围 1 - 9 中的一个字符,因此它可能符合您的预期。同样,它只匹配一个字符。
最后,{DIGIT}
匹配名称DIGIT
的扩展。我假设你有这个定义:
DIGIT [0-9]
在定义部分的某处。 (顺便说一句,我注意到你可能刚刚使用了明确的字符类[:digit:]
,你不需要定义它。)接下来是*
,这意味着它会匹配{DIGIT}
定义的零次或多次重复。
现在,匹配该模式的字符串示例:
|42
一些与该模式不匹配的字符串示例:
-7 # The pattern must start with |, + or "
42 # Again, the pattern must start with |, + or "
+0 # The character following the + must be in the range [0-9]
同样,一旦[...]
表达式被简化,你的浮动模式就会变成(每行写出一个单独的部分,使其更加明显):
["+|] # i.e. the set " + |
["0.|[1-9] # i.e. the set " 0 | [ 1 2 3 4 5 6 7 8 9
{DIGIT}* # Any number of digits
"." # A single period
] # A single ]
{DIGIT}+ # one or more digits
所以这是一个可能的匹配:
"..]3
我会跳过写出解决方案的原因,因为我认为你自己做这件事会从中受益更多。
现在,其他问题:
某些规则应与0
匹配。如果您不想允许前导零,则需要将其作为单独的规则。
使用可选运算符(?
)表示前面的对象是可选的。例如。 "foo"?
匹配三个字符 f , o , o (按顺序)或匹配空字符串。您可以使用它来使标志可选。
问题不在于abc123
的匹配,就像你的问题一样。 (F)lex总是为您提供最长的匹配,并且唯一可以匹配起始字符a
的规则是字符串规则,因此它将允许字符串规则尽可能地继续。它始终匹配abc123
的所有内容。但是,它也会匹配123
,您可能希望将其与数字规则匹配。这里,其他(f)lex匹配标准发挥作用:当有两个或更多规则可以完全匹配相同的字符串,并且没有规则可以匹配更长的字符串时,(f)lex首先选择规则在文件中。因此,如果您希望将数字优先于字符串,则必须将数字规则放在(f)lex文件中,而不是字符串规则。
我希望能为您提供有关如何解决问题的一些想法。