正则表达式 - 匹配可选重复的捕获组模式

Regex - match an optionally repeated pattern of capture groups

抱歉不知道如何准确表达这个问题。可能还有更好的标题。我乐于接受建议。

我有以下科目:

(Field1 = 'Value1') and (Field2 = 'Value2')

(Field1 = 'Value1') and (Field2 = 'Value2') or (Field3 = 'Value3')

我想以这样一种方式进行匹配,即我在组中的 () 和组中的每个连词之间都有每件事。因此,对于第二个,

的一些变体
0: Field1 = 'Value1'
1: and
2: Field2 = 'Value2'
3: or
4: Field3 = 'Value3'

好消息是,我有第一个可用的正则表达式:

\(([A-Za-z0-9\s\'=]+)\) (and|or) \(([A-Za-z0-9\s\'=]+)\)

https://regex101.com/r/hMXAXS/1

但是(在第二个主题上)它与第三个“和()”不匹配。我需要支持任意数量的组。我可以将其修改为仅查找“and ()”,但它与第一​​组不匹配。

如何让正则表达式执行此操作?我要么需要“重复计算”一些组(这很好),要么有一些其他方式来选择性地查找其他模式并匹配它们。

感谢您的帮助!

PS:我能够让我的应用程序使用正则表达式 ((and|or) \(([A-Za-z0-9\s\'=]+)\))+,然后接受第一组永远不会匹配并创建应用程序逻辑来支持它。尽管如此,我敢打赌还有更好的方法。

您可以在此处使用 preg_match_all 和正则表达式模式 (?<=\()(.*?)(?=\))|(?:and|or),如下所示:

$input = "(Field1 = 'Value1') and (Field2 = 'Value2') or (Field3 = 'Value3')";
preg_match_all("/(?<=\()(.*?)(?=\))|(?:and|or)/", $input, $matches);
print_r($matches[0]);

这会打印:

Array
(
    [0] => Field1 = 'Value1'
    [1] => and
    [2] => Field2 = 'Value2'
    [3] => or
    [4] => Field3 = 'Value3'
)

如果您不担心括号表达式中可能存在定界词或括号的边缘情况,那么 preg_split() 会生成所需的平面数组。

代码:(Demo)

$input = "(Field1 = 'Val and ue1') and (Field2 = 'Valu or e2') or (Field3 = 'Value3')";
var_export(
    preg_split(
        "~^\(|\)$|\) (and|or) \(~",
        $input,
        0,
        PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE
    )
);

输出:

array (
  0 => 'Field1 = \'Val and ue1\'',
  1 => 'and',
  2 => 'Field2 = \'Valu or e2\'',
  3 => 'or',
  4 => 'Field3 = \'Value3\'',
)

或者通过 pre-trimming 最外面的括号简化模式。 (Demo)

var_export(preg_split("~\) (and|or) \(~", trim($input, '()'), 0, PREG_SPLIT_DELIM_CAPTURE));

您还可以使用继续元字符 \G 从上一个匹配项的末尾继续匹配:(Demo) This takes 88 steps 与 Tim 的模式相比,后者需要 280 步来解析字符串。

$input = "(Field1 = 'Val and ue1') and (Field2 = 'Valu or e2') or (Field3 = 'Value3')";
preg_match_all('~(?:^\(|\G(?!^)(?:\) | \())\K(?:(?:and|or)|[^)]+)~', $input, $m);
print_r($m[0]);

在提问者接受了不提供问题中陈述的输出数组结构的答案后进行编辑:(Demo)

preg_match_all("~\((\S+ = '.*?')\) ?(or|and)?~", $input, $m, PREG_SET_ORDER);
print_r($m);

这不会检查括号表达式是否出现在连词之后。此外,在迭代匹配时,将需要进行额外检查以查看是否声明了第三组 ([2])。

Array
(
    [0] => Array
        (
            [0] => (Field1 = 'Val and ue1') and
            [1] => Field1 = 'Val and ue1'
            [2] => and
        )

    [1] => Array
        (
            [0] => (Field2 = 'Valu or e2') or
            [1] => Field2 = 'Valu or e2'
            [2] => or
        )

    [2] => Array
        (
            [0] => (Field3 = 'Value3')
            [1] => Field3 = 'Value3'
        )
)

如果您同意每场比赛分三组...

1 = 钥匙 2 = 值 3 = 连词

那么这个正则表达式也将允许在值中使用括号。

/\((.*?) = '(.*?)'\) ?(and|or)?/gm

这会导致此字符串的这些匹配...

(Field1 = 'Value1') and (Field2 = '(in parenthesis)') and (Field3 = 'Value3')