Php 正则表达式可选重复组

Php 正则表达式可选重复组,php,regex,pcre,Php,Regex,Pcre,假设以下字符串: 一些文本在这里[baz | foo]和这里[foo | bar | baz],甚至在这里[option]。 我只找到了这个丑陋的正则表达式(): 关键是我需要用方括号将匹配项分组。 因此,目前我确实有我需要的结果: [ { "match": 1, "children": [ { "group": 1, "start": 16, "end": 19, "value": "baz"

假设以下字符串:

一些文本在这里[baz | foo]和这里[foo | bar | baz],甚至在这里[option]。

我只找到了这个丑陋的正则表达式():

关键是我需要用方括号将匹配项分组。 因此,目前我确实有我需要的结果:

[
  {
    "match": 1,
    "children": [
      {
        "group": 1,
        "start": 16,
        "end": 19,
        "value": "baz"
      },
      {
        "group": 2,
        "start": 20,
        "end": 23,
        "value": "foo"
      }
    ]
  },
  {
    "match": 2,
    "children": [
      {
        "group": 1,
        "start": 35,
        "end": 38,
        "value": "foo"
      },
      {
        "group": 2,
        "start": 39,
        "end": 42,
        "value": "bar"
      },
      {
        "group": 3,
        "start": 43,
        "end": 46,
        "value": "baz"
      }
    ]
  },
  {
    "match": 3,
    "children": [
      {
        "group": 1,
        "start": 63,
        "end": 69,
        "value": "option"
      }
    ]
  }
]
结果是正确的,但regex仅限于模式中重复块的数量。
是否有一些解决方法使其与sqare括号内的所有选项相匹配?

您将无法在模式内递归生成捕获组,因为引擎不提供这种功能。因此,您有两种选择:

  • 基于管道引用数构建正则表达式 输入字符串中的
    |
  • 通过这种方式,您可以构建单个正则表达式,其中包含最可能重复的
    ([^][|]+)
    模式,这些模式将根据您的需要进行组匹配:

    $pattern = (function () use ($string) {
        $array = [];
        for ($i = 0; $i <= substr_count($string, "|"); $i++) {
            $array[] = $i == 0 ? '([^][|]+)' : '([^][|]+)?';
        }
        return implode("\|?", $array);
    })();
    
    熟食正则表达式应为:

    ~\[([^][|]+)\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?]~
    
    Array
    (
        [0] => Array
            (
                [0] => baz
            )
    
        [1] => Array
            (
                [0] => you
                [1] => him
                [2] => her
                [3] => foo
                [4] => bar
                [5] => baz
                [6] => foo
                [7] => option
                [8] => test
            )
    
        [2] => Array
            (
                [0] => another
            )
    
    )
    

    然后你可以简单地使用它:

    preg_match_all("~\[$pattern]~", $string, $matches, PREG_SET_ORDER);
    

    这是一个解决方案,表明您可以在构建正则表达式时节省时间并避免头痛,而正则表达式并不是一个简单方便的解决方案

  • 受益于其他语言功能
  • 上述解决方案不会带来固溶体。它正在做许多不需要的工作。以下代码不适合此工作:

    // Capture strings between brackets
    preg_match_all('~\[([^]]+)]~', $string, $matches);
    
    $groups = [];
    
    foreach ($matches[1] as $values) {
        // Explode them on pipe
        $groups[] = explode('|', $values);
    }
    
    产出将是:

    ~\[([^][|]+)\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?]~
    
    Array
    (
        [0] => Array
            (
                [0] => baz
            )
    
        [1] => Array
            (
                [0] => you
                [1] => him
                [2] => her
                [3] => foo
                [4] => bar
                [5] => baz
                [6] => foo
                [7] => option
                [8] => test
            )
    
        [2] => Array
            (
                [0] => another
            )
    
    )
    

    您可以使用
    preg\u replace\u callback
    提取
    []
    之间的所有值,然后在
    上分解。使用PCRE样式的引擎,您将只能获得固定的捕获组匹配。如果对较大组中的捕获组进行量化,则如果捕获组可以再次匹配,则会覆盖这些捕获组。这在网络中不是问题。因此,您可以按照chris85所提到的方式进行操作,也可以使用
    \G
    构造在括号内挑出单个值(每个匹配1个)。@chris85当然可以这样做。但是我想从regex输出中得到所有的值,你说的regex输出是什么意思?这都是正则表达式的输出。记住,你不可能一次就得到它。你知道,即使使用
    \G
    锚,你也需要一个回调来查看它是否是一组新的括号(基于匹配的组)。恐怕回电话是没办法的。您可以使用split将每个
    […]
    放在括号内,然后在
    |
    上拆分。基本上是两个分裂。这是唯一的选择,抱歉。