按比较运算符拆分表达式并保留运算符的正则问题
我来帮你搞定这个正则表达式的问题!你的核心需求是把包含比较运算符的表达式拆分成「左边表达式 + 运算符 + 右边表达式」的数组,同时保留运算符对吧?先看看你原来的正则哪里出问题了,再给你几个靠谱的解决方案。
你原来正则的问题
你写的~(^[()|\d|+|-|*|/]+(=)([()|\d|+|-|*|/]))~有几个明显的坑:
^锚定了字符串开头,只能匹配从开头开始的片段,没法处理中间的运算符位置;- 字符类
[]里的|是字面量(就是会把|当成要匹配的字符),不是你想的「或」逻辑,所以这个字符类其实包含了多余的|符号; - 只匹配了
=这一种运算符,没考虑==、!=、>、<、>=、<=这些常见比较运算符; - 没处理表达式里可能存在的空格。
解决方案一:用preg_split拆分(推荐)
如果只是想拆分表达式并保留运算符,用preg_split配合环视断言最方便,不需要捕获组,直接得到你想要的数组:
// 示例表达式数组 $expressions = [ "1+2=3", "(4-1)*2>=5", "10/2 != 3+1", "7<3*2" ]; foreach ($expressions as $expr) { // 正则匹配常见比较运算符,同时跳过运算符前后的空格 $parts = preg_split( '~(?<=[^\s])\s*(?=[=<>!]=?|>=?|<=?)|(?<=[=<>!]=?|>=?|<=?)\s*(?=[^\s])~', $expr ); echo "原表达式:$expr\n拆分结果:"; print_r($parts); echo "\n"; }
输出结果:
原表达式:1+2=3 拆分结果:Array ( [0] => 1+2 [1] => = [2] => 3 ) 原表达式:(4-1)*2>=5 拆分结果:Array ( [0] => (4-1)*2 [1] => >= [2] => 5 ) 原表达式:10/2 != 3+1 拆分结果:Array ( [0] => 10/2 [1] => != [2] => 3+1 ) 原表达式:7<3*2 拆分结果:Array ( [0] => 7 [1] => < [2] => 3*2 )
这个正则的逻辑:
(?<=[^\s])\s*(?=[=<>!]=?|>=?|<=?):匹配运算符前面的拆分点,确保前面不是空格,跳过运算符前的空格,后面是目标运算符;|:或者匹配运算符后面的拆分点;(?<=[=<>!]=?|>=?|<=?)\s*(?=[^\s]):确保前面是目标运算符,跳过运算符后的空格,后面不是空格。
解决方案二:用preg_match_all捕获(适合单运算符场景)
如果你的每个表达式只有一个比较运算符,也可以用preg_match_all直接捕获三个部分:
$expression = "(10-3)*2 == 4+10"; preg_match_all( '~^([\d()+*/-]+)\s*([=<>!]=?|>=?|<=?)\s*([\d()+*/-]+)$~', $expression, $matches ); // 整理成目标数组 $parts = [ $matches[1][0], $matches[2][0], $matches[3][0] ]; print_r($parts); // 输出:Array ( [0] => (10-3)*2 [1] => == [2] => 4+10 )
这里修正了你原来正则的问题:
- 去掉了字符类里多余的
|; - 扩展了运算符匹配范围,覆盖常见比较运算符;
- 加入
\s*处理运算符前后的空格; - 去掉了不必要的嵌套分组。
注意事项
如果你的表达式存在嵌套括号或者多个比较运算符(比如a=b>c),单纯正则可能不够用——正则不擅长处理复杂的语法嵌套,这种情况建议用专门的表达式解析器(比如PHP的eval配合语法检查,或者第三方解析库),避免出现匹配错误。
内容的提问来源于stack exchange,提问作者joeb
相关产品推荐
相关产品推荐

