假设我正在构建一个编译器,我希望词法分析器识别C语言的整数,我可以指定例如整数应该在-2,147,483,648和2,147,483,647之间,长整数可以是64位吗?我觉得我的问题很愚蠢,但我想知道它是否可行......谢谢
答案 0 :(得分:5)
是的可以完成,但你不那样做!
剧透警告:您最好使用strtol
,我会在 long 答案中告诉您原因。
这是因为这样的任务意味着对正则表达式进行大量处理,而该测试可以用您喜欢的语言进行很少的处理(将以下内容视为伪代码):
if (str_to_int(s) > CMIN && str_to_int(s) < CMAX)
嗯,实际上你可能会告诉我&#34; 但是如果它是一个int,它会溢出!&#34;。但是有一些技术可以检测到:
并且他们都没有使用正则表达式!
但是,无论如何,当C标准库中已经为您完成这项工作时,您不需要遇到太多麻烦: strtol
功能!引用手册:
strtol()函数返回转换结果,除非该值会下溢或溢出。如果发生下溢,strtol()将返回LONG_MIN。如果发生溢出,strtol()将返回LONG_MAX。在这两种情况下,errno都设置为ERANGE。对于strtoll()(LLONG_MIN和LLONG_MAX而不是LONG_MIN和LONG_MAX)也是如此。
为什么它会很大?这是因为正则表达式是一个查看字符流的自动机。当匹配时,您沿着自动机移动。基本上,您需要:
-
2
开头,则只能跟0
或1
,2
开头,后跟1
,则只能跟0
,1
,2
,{{1 }或3
4
开头,后跟2
,然后是1
,则只能跟4
,1
, 2
,3
... 4
7
开头,则以...结尾,并以2
结尾,但如果它以7
开头,然后是-
,则需要以2
结束(所以基本上你必须将所有先前的条件复制到另一个以该结尾的子图中)这看起来有点像:
6
由以下自动机直观表示(点击要播放的图像):
我不确定会有多正确,因为我可能错过了边缘情况,但我希望我明确表示它与用你最喜欢的语言做的比较。如果你真的解析了这么大的自动机,它会:
所有这些都不是做一些可以在使用正则表达式做同样事情的复杂性的1/100的操作中完成的事情。
因此,如果您因为编程错误而不想杀死小印章,请不要使用regexp来处理它没有被设计的东西。
为了更好地理解自动机是什么,正则表达式是如何工作的,何时使用它是个好主意,当它是一个小密封杀死它时,我只能建议你看看以下课程:< / p>
^(
(
\d|\d\d|\d\d\d|\d\d\d\d|\d\d\d\d\d|\d\d\d\d\d\d|
\d\d\d\d\d\d\d|\d\d\d\d\d\d\d\d|\d\d\d\d\d\d\d\d\d|
[0-2][0-1][0-4][0-7][0-4][0-8][0-3][0-6][0-4][0-8]
)|
-(
\d|\d\d|\d\d\d|\d\d\d\d|\d\d\d\d\d|\d\d\d\d\d\d|
\d\d\d\d\d\d\d|\d\d\d\d\d\d\d\d|\d\d\d\d\d\d\d\d\d|
[0-2][0-1][0-4][0-7][0-4][0-8][0-3][0-6][0-4][0-7]
)
)$
:Does strtol("-2147483648", 0, 0) overflow if LONG_MAX is 2147483647? 这里是@ Andie2302答案的可视化:
strtol
通过匹配的自动机:
还是不相信?
HTH
答案 1 :(得分:1)
这个正则表达式应该有效:
-\b(?:214748364[0-8]|21474836[0-3][0-9]|2147483[0-5][0-9]{2}|214748[0-2][0-9]{3}|21474[0-7][0-9]{4}|2147[0-3][0-9]{5}|214[0-6][0-9]{6}|21[0-3][0-9]{7}|20[0-9]{8}|1[0-9]{9}|[1-9][0-9]{1,8}|[0-9])\b|\b(?:214748364[0-7]|21474836[0-3][0-9]|2147483[0-5][0-9]{2}|214748[0-2][0-9]{3}|21474[0-7][0-9]{4}|2147[0-3][0-9]{5}|214[0-6][0-9]{6}|21[0-3][0-9]{7}|20[0-9]{8}|1[0-9]{9}|[1-9][0-9]{1,8}|[0-9])\b