Php 按正则表达式拆分自定义条件
我正忙于编写一个后端模块,用户可以在其中创建自己的条件/规则。现在我想把一个条件分成几个部分 例如: 条件:{variable}>100 条件:{variable}=={anotherVariable}或{var}{variable}=={anotherVariable} [1] =>或 [2] =>{var}和 [2] =>{var}和 [4] =>{variable}==某个字符串 ) 之后,我必须将比较分为三部分: 比较:{variable}=={anotherVariable}Php 按正则表达式拆分自定义条件,php,regex,preg-match-all,Php,Regex,Preg Match All,我正忙于编写一个后端模块,用户可以在其中创建自己的条件/规则。现在我想把一个条件分成几个部分 例如: 条件:{variable}>100 条件:{variable}=={anotherVariable}或{var}{variable}=={anotherVariable} [1] =>或 [2] =>{var}和 [2] =>{var}和 [4] =>{variable}==某个字符串 ) 之后,我必须将比较分为三部分: 比较:{variable}=={anotherVariable} //所
//所需的输出
//允许的比较运算符为:==,!=,>,>=,==/比较运算符
[2] =>{anotherVariable}//比较
)
我现在在正则表达式上苦苦挣扎了好几个小时,但没有得到所需的输出。为了让它更简单,我假设字符串在双引号之间 模式的第一部分使用命名的子模式定义(
(?(DEFINE)…)
)所需的元素。首先是简单元素(比较运算符、布尔运算符、操作数),然后是更复杂的元素(原子条件、条件、检查)。每个子模式都可以和其他子模式以及子模式本身一起定义
一旦定义部分关闭,主模式开始并在每次迭代中捕获名为capture的“标记”内的三个可能元素:布尔运算符、原子条件(即最可能的基本条件)或括号内的整个条件
要成功,主模式必须通过两个入口点中的一个,第一个(仅使用一次)是子模式\g
。此子模式确保整个字符串从头到尾格式良好,并且由于它是以\a
开头的零宽度断言,因此强制标记搜索从字符串的开头开始。第二个输入点是(?!\A)\G
,表示“不在字符串开头,与前一个匹配项相邻”。此条目用于所有其他匹配项
名为capture的\g
仅在此处由递归函数使用。如果捕获存在,则标记是括号内的一个完整条件,需要重新分析以生成数组
define('PATTERN', <<<'EOD'
~
(?(DEFINE)
(?<comp_op> [=!]= | >=? | <[=>]? )
(?<bool_op> OR | AND )
(?<operand> { \w+ } | -?\d+ | "[^"]+" ) # you can improve the " pattern
(?<at_cond> \g<operand> \s+ \g<comp_op> \s+ \g<operand> ) # atomic cond
(?<cond> \g<at_cond> (?> \s+ \g<bool_op> \s+ \g<cond> )* | \( \g<cond> \) )
(?<check> (?= \A \s* \g<cond> \s* \z ) ) # checks the whole string format
)
(?: \g<check> \s* | (?!\A)\G \s+)
(?| (?<token>\g<bool_op>) | (\g<at_cond>) | \( (\g<cond>) )
(?<par> \) )? # only to test if a recursion is needed
~x
EOD
);
function getTokens ($str) {
if (preg_match_all(PATTERN, $str, $matches)) {
$tokens = array();
foreach ($matches['token'] as $k=>$token) {
$tokens[] = ($matches['par'][$k]) ? getTokens($token) : $token;
}
return $tokens;
}
return false;
}
$testset = array(
'{variable} > 100',
'{variable} == {zogabu} OR {buga} <= 10',
'{meuh} == {zo} AND ({meuh} <= 10 OR {zomeuh} == "GABUZO")',
'{BU} > 3 AND ({ga} == "ZO" OR ({bu} == "GA" AND {meuh} != "GA"))' );
foreach($testset as $test_string) {
$result = getTokens($test_string);
echo "\ntest_string: $test_string\n" . print_r($result, true);
}
define('PATTERN',$token){
$tokens[]=($matches['par'][$k])?getTokens($token):$token;
}
归还$tokens;
}
返回false;
}
$testset=array(
“{variable}>100”,
{variable}={zogabu}或{buga}它们可以嵌套和和或?@anubhava是的,这将是功能的极大提升,但我在数组中没有一个很好的答案。它应该用{var}>10和({var2}==某物或{var3}==某物)来做一些事情。正则表达式可以让这两者之间的一切都存在吗()在一个新数组中?正则表达式不是这个的合适工具。你需要构建你的自定义解析器。(不解析嵌套的)。在我看来,这不是一个可以单独用正则表达式解决的问题。在我看来,你还需要添加一些编程逻辑。
// desired output
Array
(
[0] => {variable} == {anotherVariable}
[1] => OR
[2] => {var} <= 10
)
// desired output
Array
(
[0] => {variable} == {anotherVariable}
[1] => AND
[2] => {var} <= 10
[3] => AND
[4] => {variable} == some string
)
// desired output
// allowed comparison operators are: ==, !=, >, >=, <, <=, <>
Array
(
[0] => {variable} // comparison
[1] => == // comparision operator
[2] => {anotherVariable} // comparison
)
define('PATTERN', <<<'EOD'
~
(?(DEFINE)
(?<comp_op> [=!]= | >=? | <[=>]? )
(?<bool_op> OR | AND )
(?<operand> { \w+ } | -?\d+ | "[^"]+" ) # you can improve the " pattern
(?<at_cond> \g<operand> \s+ \g<comp_op> \s+ \g<operand> ) # atomic cond
(?<cond> \g<at_cond> (?> \s+ \g<bool_op> \s+ \g<cond> )* | \( \g<cond> \) )
(?<check> (?= \A \s* \g<cond> \s* \z ) ) # checks the whole string format
)
(?: \g<check> \s* | (?!\A)\G \s+)
(?| (?<token>\g<bool_op>) | (\g<at_cond>) | \( (\g<cond>) )
(?<par> \) )? # only to test if a recursion is needed
~x
EOD
);
function getTokens ($str) {
if (preg_match_all(PATTERN, $str, $matches)) {
$tokens = array();
foreach ($matches['token'] as $k=>$token) {
$tokens[] = ($matches['par'][$k]) ? getTokens($token) : $token;
}
return $tokens;
}
return false;
}
$testset = array(
'{variable} > 100',
'{variable} == {zogabu} OR {buga} <= 10',
'{meuh} == {zo} AND ({meuh} <= 10 OR {zomeuh} == "GABUZO")',
'{BU} > 3 AND ({ga} == "ZO" OR ({bu} == "GA" AND {meuh} != "GA"))' );
foreach($testset as $test_string) {
$result = getTokens($test_string);
echo "\ntest_string: $test_string\n" . print_r($result, true);
}