我正忙于编写一个后端模块,用户可以在其中创建自己的条件/规则。现在我想把一个条件分成几个部分。
例如:条件: {variable}> 100
// desired output
Array
(
[0] => {variable} > 100
)
:{变量}= = {anotherVariable}或{var} & lt; = 10
// desired output
Array
(
[0] => {variable} == {anotherVariable}
[1] => OR
[2] => {var} <= 10
)
条件: {variable} == {anotherVariable} AND {var} <= 10 AND {variable} == some string
// desired output
Array
(
[0] => {variable} == {anotherVariable}
[1] => AND
[2] => {var} <= 10
[3] => AND
[4] => {variable} == some string
)
之后,我必须将比较分成3部分:
比较:{变量}= = {anotherVariable}
// desired output
// allowed comparison operators are: ==, !=, >, >=, <, <=, <>
Array
(
[0] => {variable} // comparison
[1] => == // comparision operator
[2] => {anotherVariable} // comparison
)
我现在挣扎了几个小时正则表达式,但没有导致所需的输出。
为了更简单,我假设字符串在双引号之间。
模式的第一部分用命名的子模式定义((?(DEFINE)...)
)所需的元素。首先是简单元素(比较运算符、布尔运算符、操作数),然后是更复杂的元素(原子条件、条件、检查)。每个子模式都可以与其他子模式及其本身一起定义。
要成功,主模式必须通过两个入口点之一,第一个(只使用一次)是子模式'g<check>
。此子模式确保整个字符串从头到尾都是良好的,并且由于它是以'A
开头的零宽度断言,因此强制令牌搜索从字符串的开头开始。第二个入口点是(?!'A)'G
,表示"不在字符串的开头,与先前匹配相邻"。此条目用于所有其他匹配。
命名为'g<par>
的capture仅供递归函数使用。如果捕获存在,则令牌是括号内的一个完整条件,需要解析以生成一个数组。
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);
}