繁体   English   中英

正则表达式可选重复组

[英]regex optional repetitive group

假设以下字符串:

some text here [baz|foo] and here [foo|bar|baz] and even here [option].

我设法只通过这个丑陋的正则表达式( Regex101.com demo )进行匹配:

/(?:
  \[
    (?:
      \|?
      ([^\|\[\]]+)
    )?
    (?:
      \|?
      ([^\|\[\]]+)
    )?
    (?:
      \|?
      ([^\|\[\]]+)
    )?
  \]
)/ugx

关键是我需要用方括号将比赛分组。 所以目前我确实有需要的结果:

[
  {
    "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"
      }
    ]
  }
]

结果是正确的,但是正则表达式限于模式中重复块的数量。 有什么解决方法可以使其与方括号内的所有选项匹配?

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

  1. 构建基于管道的出现次数正则表达式| 在您的输入字符串中。

这样,您可以使用([^][|]+)大多数可能重复模式构建单个正则表达式,从而根据需要进行组匹配:

$pattern = (function () use ($string) {
    $array = [];
    for ($i = 0; $i <= substr_count($string, "|"); $i++) {
        $array[] = $i == 0 ? '([^][|]+)' : '([^][|]+)?';
    }
    return implode("\|?", $array);
})();

通过输入类似以下的输入字符串:

some text here [baz] and here [you|him|her|foo|bar|baz|foo|option|test] and even here [another].

煮熟的正则表达式为:

~\[([^][|]+)\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?]~

现场演示

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

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

现场演示

这是一种变通方法,它表明您可以节省时间并避免仅构建正则表达式时会头疼,并且正则表达式并非始终简单易用的解决方案。

  1. 受益于其他语言功能。

上述解决方法不能带来可靠的解决方案。 它正在做很多不需要的工作。 下面的代码确实适合您的工作:

// 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
        )

)

现场演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM