【问题标题】:php regex to detect text inside brackets ignoring nested bracketsphp正则表达式检测括号内的文本忽略嵌套括号
【发布时间】:2015-09-30 08:10:01
【问题描述】:

我正在尝试制作一个 php 正则表达式来解析括号中的文本字符串,同时忽略可能的嵌套括号:

假设我想要

Lorem ipsum [1. dolor sit amet, [consectetuer adipiscing] elit.]. Aenean commodo ligula eget dolor.[2. Dolor, [consectetuer adipiscing] elit.] Aenean massa[3. Lorem ipsum] dolor.

返回

[1] => "dolor sit amet, [consectetuer adipiscing] elit."
[2] => "Dolor, [consectetuer adipiscing] elit."
[3] => "Lorem ipsum"

目前为止

'/\[([0-9]+)\.\s([^\]]+)\]/gi'

但是当出现嵌套括号时它会中断。 See demo

如何从检测中忽略内括号? 提前谢谢!

【问题讨论】:

  • 因为嵌套结构,我认为regex不适合这种情况。也许一个简单的例程是更好的方法。

标签: php regex brackets


【解决方案1】:

您可以对以前的组使用递归引用:

(?<no_brackets>[^\[\]]*){0}(?<balanced_brackets>\[\g<no_brackets>\]|\[(?:\g<no_brackets>\g<balanced_brackets>\g<no_brackets>)*\])

See it in action

我们的想法是将您想要的匹配项定义为不带括号的内容,由[] 包围,或者包含一系列不带括号的内容或包含第一条规则的平衡括号。

【讨论】:

  • 我不知道命名捕获组,非常有帮助!
【解决方案2】:

您可以使用此模式在两个不同的组中捕获项目编号和以下文本。如果您确定所有项目编号都是唯一的,则可以使用简单的array_combine 构建问题中描述的关联数组:

$pattern = '~\[ (?:(\d+)\.\s)? ( [^][]*+ (?:(?R) [^][]*)*+ ) ]~x';

if (preg_match_all($pattern, $text, $matches))
    $result =  array_combine($matches[1], $matches[2]);

图案细节:

~     # pattern delimiter
\[    # literal opening square bracket
(?:(\d+)\.\s)? # optional item number (*) 
(              # capture group 2
   [^][]*+         # all that is not a square bracket (possessive quantifier)
   (?:             # 
       (?R)        # recursion: (?R) is an alias for the whole pattern
       [^][]*      # all that is not a square bracket
   )*+             # repeat zero or more times (possessive quantifier)
)
]                  # literal closing square bracket
~x  # free spacing mode

(*) 请注意,如果您希望能够将递归与 (?R) 一起使用,则项目编号部分必须是可选的 (例如,[consectetuer adipiscing] 没有项目编号。)。如果您想避免没有项目编号的方括号,这可能会出现问题。在这种情况下,如果您将可选组 (?:(\d+)\.\s)? 更改为条件语句,则可以构建更健壮的模式:(?(R)|(\d+)\.\s)

条件语句:

(?(R)        # IF you are in a recursion
             # THEN match this (nothing in our case)
  |          # ELSE
  (\d+)\.\s  #   
)

这样,项目编号就变成了必填项。

【讨论】:

    【解决方案3】:

    您可以使用递归正则表达式来获取用方括号括起来的所有子字符串,然后在array_map 内使用preg_replace 来删除括号和封闭括号:

    $str = "Lorem ipsum [1. dolor sit amet, [consectetuer adipiscing] elit.]. Aenean commodo ligula eget dolor.[2. Dolor, [consectetuer adipiscing] elit.] Aenean massa[3. Lorem ipsum] dolor.";
    preg_match_all('/\[(?>[^\[\]]|(?R))*]/', $str, $matches);
    $res = array_map(function($el) {
        return preg_replace('/^\[\d+\.(.*?)\s*\]$/s', '$1', $el); 
        },
        $matches[0]);
    print_r($res);
    

    IDEONE demo

    \[(?&gt;[^\[\]]|(?R))*] 正则表达式匹配[,然后匹配[] 或嵌套的[...] 构造。在regular-expressions.info 上查看有关使用正则表达式进行递归的更多信息。这是regex demo

    preg_repace - ^\[\d+\.(.*?)\s*\]$ - 内的正则表达式将匹配初始 [ 与 1 个或多个数字和一个句点,然后匹配并捕获其余部分,直到最终的可选空格 (\s*) 和关闭]$ 将确保括号在字符串末尾匹配)。使用$1,我们可以恢复字符串的其余部分并使用它来填充新数组。请参阅2nd regex demo here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多