【正则表达式】匹配数字或四则运算的正则表达式
⼯作中遇到个需求,要验证⽤户输⼊的字符串是否为数字或四则运算式,过程中遇上了⼏个坑,虽然最后也没能完全解决这个问题,不过总算是有了个能⽤的正则表达式。
^(\-?\d+[\.\+\-\*\/]?)*\-?\d+$
该正则表达式:
可以匹配数字,正数负数⼩数皆可。
可以匹配数字,⼩数点以及 + - * / 组成的四则运算。
不⽀持优先级,即不⽀持括号 ()。
不⽀持带正号的正数出现在表达式开头,即不⽀持 +1 这种正数作为四则运算的开头。
不⽀持优先级这个问题⽐较难解决,因为正则表达式是有穷⾃动机,带优先级的四则运算是上下⽂⽆关语法,等价于⾮确定性下推⾃动机,正则表达式解决不了这个问题,外加个⼈能⼒限制,所以只能⽤在匹配时替换掉括号的临时⽅案代替。
不⽀持带正号的数字开头则是可以解决的,将开头第三个字起的 \-? 换成 [\+\-]? 即可,不过我想也不会有⼏个⼈会⽆聊到会这么输⼊吧...
构建过程
⾸先是正整数匹配
正整数匹配是最简单的,\d可以匹配数字,正整数是1个或多个数字重复,⽤+匹配,可得:
\d+
然后是增加负整数的匹配
负整数和正整数的区别就是负号,负号的出现的次数只会是负整数1次,正整数0次,⽤?匹配,可得:
\-?\d+
第三步增加⼩数点的匹配
⼩数点也同样有两种情况,整数时出现0次,⼩数时出现1次,⼩数的⼩数点后跟数字重复1次或更多次,可得:
\-?\d+(\.\d+)?
第四步增加四则运算的开头
四则混合运算,会有括号或数字开头两种情况,数字会有正负整数或⼩数开头的四种情况,但不考虑括号,并且已经在第三步得到了匹配任何数字的表达式的情况下,四则运算只会以数字开头,所以直接:
^\-?\d+(\.\d+)?
第五步增加减乘除符号
加减乘除只会跟在数字后⾯,并且只会出现⼀次,可得:
^\-?d+(\.\d+)?[\+\-\*\/]
第六步增加四则运算的结尾
不考虑括号的情况下,四则运算的结尾同开头,只会出现数字,所以:
^\-?d+(\.\d+)?[\+\-\*\/]\-?\d+(\.\d+)?$
第七步增加四则运算的中间部分
js正则表达式数字和小数点第六步得到的正则表达式只能匹配两个数字之间的加减乘除,⽽四则运算是多个数字之间的加减乘除,这⼀步需要解决这个问题。
⾸先随⼿写出⼏个不带括号的四则运算式:
-10+5-3.6*4/8.5
8*1/4+-45+8*21
2--8*5.5/-7
分离开头的数字带符号,以及末尾的数字:
仔细观察可以得出以下规律:四则运算的中间部分,也是以数字后接运算符号的⼀个个节点组成的,如下:
中间的数字后接运算符号节点,可以⽤第五步的表达式,去掉匹配开头的 ^符号,即 \-?d+(\.\d+)?[+\-\*/] 来匹配,以为数字接符号节点,并且这个节点重复0次或任意次,可得:
^\-?d+(\.\d+)?[\+\-\*\/](\-?d+(\.\d+)?[\+\-\*\/])*\-?\d+(\.\d+)?$
第⼋步优化重复部分
第七步中的表达式有明显重复的部分,作为程序员看到重复就会想到这部分可以优化⼀下,⽽ XX* 形式的正则表达式,在正则中可以⽤ X+来代替,可得:
^(\-?d+(\.\d+)?+[\+\-\*\/])+\-?\d+(\.\d+)?$
不过这个表达式,可以匹配四则运算表达式但不能匹配数字了,⽽这⼆者之间的区别,在于数字接符号的节点出现0次还是出现更多次,即正则符号的 ***** ,故只需要将数字接符号的节点后的 +,替换为 ***** 就可以了:
^(\-?d+(\.\d+)?[\+\-\*\/])*\-?\d+(\.\d+)?$
最后⼀步优化⼩数点的部分
第⼋步中得到的表达式,已经可以作为匹配数字或四则运算的正则表达式了,不过在观察四则运算式的时候,我还发现,⼩数点,和加减乘除出现的地⽅其实是⼀致的,如下:
-10+ 5- 3. 6* -4/ 8. 5
8* 1/ 4+ -45+ 8* 21
2- -8* 5. 5/ -7
带或不带负号的数字,后接⼩数点或加减乘除,就组成了节点,节点重复任意次。
这样的话,将⼩数点视为加减乘除的同位,对表达式再次进⾏简化,可得:
^(\-?\d+[\.\+\-\*\/]?)*\-?\d+$
这样就得到开始的正则表达式了。
总结
没啥好总结的,不过这个过程真有趣。
总结记录⼀下,以后可能⽤的到。
以后也许会试试把括号的问题解决了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论