例:a1=1&&a2=2&&a3=3&&(a4=1||a5=2||(a6=3&&a7=4))
匹配结果:
array:7 [
0 => "a1=1"
1 => "a2=2"
2 => "a3=3"
3 => "a4=1"
4 => "a5=2"
5 => "a6=3"
6 => "a7=4"
]
例:a1==1 && a2==3 && ((a4a5+(a6+a7)/3)>10 || (a1 /((a2/100)(a2/100))) >= 28 || (a3*((a1)+(a4-a5)+(a2))>4) ) && a10==6 || a9==9 && (a3>4 || a5 <6)
匹配结果:
array:9 [
0 => "a1==1"
1 => "a2==3"
2 => "a4a5+(a6+a7)/3>10"
3 => "a1/((a2/100)(a2/100))>=28"
4 => "a3*((a1)+(a4-a5)+(a2))>4"
5 => "a10==6"
6 => "a9==9"
7 => "a3>4"
8 => "a5<6"
]
1
SmallTeddy 2020-12-18 11:10:24 +08:00
你这个 split('&&')拆分开就行吧
|
2
Cbdy 2020-12-18 11:41:40 +08:00 via Android
用什么编程语言?我用 Perl 写个你能用吗?
|
3
conanforever22 2020-12-18 13:10:05 +08:00
如果是 shell, 用`tr`把'|&()'替换成'\n\n '然后 trim 掉前后空格就行了
echo 'a1=1&&a2=2&&a3=3&&(a4=1||a5=2||(a6=3&&a7=4))' | tr '|&()' '\n\n ' |
4
klzhoushuai OP |
5
cheese 2020-12-18 13:14:41 +08:00
@klzhoushuai #4 两次循环就好了,先判断&&再循环合并||。不需要正则,这个正则做还挺麻烦的
|
6
lululau 2020-12-18 13:23:28 +08:00 1
这个问题和正则没关系,请自行搜索“parser for mathematical expression”
|
7
SmallTeddy 2020-12-18 13:34:56 +08:00
@lululau 我觉得也和正则没关系
|
8
klzhoushuai OP /**
* 拆分公式 * @param $formula * @return array */ public function splitFormula($formula) { $formula = $t = str_replace(' ', '', $formula); $formula = str_replace(['&&', '||'], [';', ';'], $formula); $result = explode(';', $formula); foreach ($result as $key => $value) { while (true) { $left = substr_count($value, '('); $right = substr_count($value, ')'); if ($left === $right) break; if ($left > $right) { $value = substr_replace($value, '', strpos($value, '('), 1); } else { $value = substr_replace($value, '', strrpos($value, ')'), 1); } } $result[$key] = $value; } return $result; } |
9
klzhoushuai OP @klzhoushuai 用了一个比较笨的方法写的
|
10
rrfeng 2020-12-18 14:04:53 +08:00
这个难点在括号。写个 parser 吧。
|
11
ipwx 2020-12-18 14:07:00 +08:00
1. 没看懂楼主想干嘛。
2. 递归文法的解析我记得超出了 regex 的范畴。 |
12
zy445566 2020-12-18 14:29:43 +08:00
这不是正则的范畴了,这是语法解析
|
13
gIQgxDI09Jflpdc2 2020-12-18 15:53:17 +08:00
@klzhoushuai
分两步。 1 用正则取出 &&或者|| 符号中间的内容。 2 利用字符串替换多余的括号。 PHP 写法如下: ``` // 两个字符串例子 $str1 = 'a1=1&&a2=2&&a3=3&&(a4=1||a5=2||(a6=3&&a7=4))'; $str2 = 'a1==1 && a2==3 && ((a4a5+(a6+a7)/3)>10 || (a1 /((a2/100)(a2/100))) >= 28 || (a3*((a1)+(a4-a5)+(a2))>4) ) && a10==6 || a9==9 && (a3>4 || a5 <6)'; preg_match_all('/[^&|^\|]+/', $str1, $match);//提取 &&或者||符号中间的内容。 if (!empty($match[0])) { foreach ($match[0] as &$value) { $value = trim(removeBrackets($value));//移除多余的括号 } } var_dump($match); /** * 移除多余的括号 * @param $string * @return string|string[]|null */ function removeBrackets($string) { // 左括号 右括号 默认 0 个 $leftBracket = $rightBracket = 0; // 计算括号个数 for($i=0;$i<strlen($string);$i++){ if ($string[$i] == '(') { $leftBracket++; } elseif ($string[$i] == ')') { $rightBracket++; } } $abs = abs($leftBracket - $rightBracket);//括号个数的差值 if ($abs == 0) { return $string; } if ($leftBracket > $rightBracket) {// 如果 左括号多,移除多余的 $string = preg_replace('/\(/', '', $string, $abs); } elseif ($leftBracket < $rightBracket) {// 如果 右括号多,移除多余的 $string = preg_replace('/\)/', '', $string, $abs); } return $string; } ``` 两个例子转换结果如下: ``` [ "a1=1", "a2=2", "a3=3", "a4=1", "a5=2", "a6=3", "a7=4" ] 第二个和你期待的有一点点不一样,但是我觉得应该也符合你预期。 [ "a1==1", "a2==3", "(a4a5+(a6+a7)/3)>10", "(a1 /((a2/100)(a2/100))) >= 28", "(a3*((a1+(a4-a5)+(a2))>4) )", "a10==6", "a9==9", "a3>4", "a5 <6" ] ``` |
14
gIQgxDI09Jflpdc2 2020-12-18 15:54:32 +08:00
为什么我的 markdown 语法没生效!排版全乱了,难受。
谁能告诉我为什么吗? |
15
gIQgxDI09Jflpdc2 2020-12-18 15:59:43 +08:00
原来回复还不支持 markdown 。Fine~
|
16
gIQgxDI09Jflpdc2 2020-12-18 16:19:28 +08:00 1
|
17
klzhoushuai OP @alex2019
好像有点问题,如果字符串为:a1=1&&a2=2&&a3=3&&(a4=1||a5=2||(a6=3&&a7=4 &&((a8+a9)/2>50 || a10/((a1+a2)*10)>20))) 解析出来的最后的一个表达式就有问题了吧:a10/((a1+a2*10>20)) ,正确的结果应该是:a10/((a1+a2)*10)>20 用 $string = preg_replace('/\)/', '', $string, $abs); 匹配时这个是从左到右匹配的 |
18
gIQgxDI09Jflpdc2 2020-12-18 17:43:23 +08:00
@klzhoushuai 那你就把字符串反转之后。再调用 [去掉括号] 方法。
|