【问题标题】:Split a custom condition by regular expression通过正则表达式拆分自定义条件
【发布时间】:2014-07-31 15:36:43
【问题描述】:

我正忙于编写一个后端模块,用户可以在其中创建自己的条件/规则。现在我想将一个条件分成几部分。

例如:

条件:{变量} > 100

// desired output
Array
(
    [0] => {variable} > 100
)

条件:{variable} == {anotherVariable} OR {var}

// desired output
Array
(
    [0] => {variable} == {anotherVariable}
    [1] => OR
    [2] => {var} <= 10
)

条件:{variable} == {anotherVariable} AND {var}

// desired output
Array
(
    [0] => {variable} == {anotherVariable}
    [1] => AND
    [2] => {var} <= 10
    [3] => AND
    [4] => {variable} == some string
)

然后我必须将比较分成 3 个部分:

比较: {variable} == {anotherVariable}

// desired output
// allowed comparison operators are: ==, !=, >, >=, <, <=, <>
Array
(
    [0] => {variable}               // comparison
    [1] => ==                       // comparision operator
    [2] => {anotherVariable}        // comparison
)

我现在用正则表达式苦苦挣扎了好几个小时,但没有得到想要的输出。

【问题讨论】:

  • 它们可以嵌套ANDOR吗?
  • @anubhava 是的,这将极大地提升功能,但我的阵列中没有很好的答案。它应该使用 {var} > 10 AND ({var2} == something OR {var3} == something)。是否可以使用正则表达式将 () 之间的所有内容都放在一个新数组中?
  • Regex 不是解决此问题的正确工具。您将需要构建您的自定义解析器。
  • 在我看来这不是一个可以单独通过正则表达式解决的问题。在我看来,您还需要添加一些编程逻辑。

标签: php regex preg-match-all


【解决方案1】:

为了更简单,我假设字符串在双引号之间。

模式的第一部分定义((?(DEFINE)...))具有命名子模式的所需元素。首先是简单元素(比较运算符、布尔运算符、操作数),然后是更详细的元素(原子条件、条件、检查)。每个子模式都可以与其他子模式和自身一起定义。

一旦定义部分关闭,主模式开始并在每次迭代中捕获名为 capture 的“令牌”内的三个可能元素:布尔运算符,原子条件(即最可能的基本条件),或括号内的整个条件

要成功,主模式必须通过两个入口点之一,第一个(仅使用一次)是子模式\g&lt;check&gt;。此子模式确保整个字符串从头到尾的格式正确,并且由于它是一个以\A 开头的零宽度断言,因此强制令牌搜索从字符串的开头开始。第二个入口点是(?!\A)\G,意思是“不在字符串的开头,与先例匹配”。此条目用于所有其他匹配项。

\g&lt;par&gt; 命名的捕获在这里只供递归函数使用。如果捕获存在,则标记是括号内的完整条件,需要重新解析以生成数组。

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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多