正则表达式匹配方括号后跟括号,其中方括号也可以包含其他方括号

时间:2012-11-08 23:05:36

标签: php regex preg-replace preg-match-all

我有一些这样的文字,它是以自定义降价格式编写的。例如:

[Lorem ipsum] 
Dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 

[Ut wisi] 
[Enim ad minim veniam](a), quis nostrud exerci tation ullamcorper. 
suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat. 
Vel illum dolore eu feugiat nulla facilisis at vero.
[Ros et accumsan et iusto odio dignissim](b) qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 

[[Nam liber]](c)
Tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum.

正如你所看到的那样,有方括号的方括号,并且有方括号后跟括号括起来,这是我试图与正则表达式匹配的字母。我试图使用的正则表达式是:

preg_match_all("#\[(.*?)\]\(([a-z]+)\)#is",$html,$matches)

这个问题是从[Lorem ipsum]到(a)的结尾匹配。

我也可以使用以下内容,但是我需要能够在方括号中添加标题,这样才能正常工作:

preg_match_all("#\[([^]]+)\]\(([a-z]+)\)#is",$html,$matches)

经过一些阅读,我怀疑我需要的是一个先行,但是我无法绕过他们。任何帮助非常感谢。


澄清

我基本上希望能够使用方括号/括号组合来包装某些文本的任何部分,然后能够将它们与正则表达式匹配,而不会在任何地方引起冲突。示例文本:

[[Lorem ipsum]](a)
Dolor sit amet, [consectetuer adipiscing elit](b), sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 

期望的比赛:

[[Lorem ipsum]](a)
[consectetuer adipiscing elit](b)

或者......更复杂

[[Lorem ipsum]
Dolor sit amet, sed diam nonummy nibh euismod](a) tincidunt ut laoreet dolore magna aliquam erat volutpat. 

期望的比赛:

[[Lorem ipsum]
Dolor sit amet, sed diam nonummy nibh euismod](a)

有可能吗?

2 个答案:

答案 0 :(得分:1)

m.buettner的回答非常好。它既准确又记录良好(它得到了我的投票,值得继续选择答案)。我真的很喜欢正则表达式在自由间隔模式下自我记录的事实。但是,为了完整起见,(并且作为另一种评论风格的演示)这里是一个等效(但稍微更高效)的正则表达式解决方案:

preg_match_all('/
    # Match a "[...[...]...[...]...](...)" structure.
    \[               # Literal open square bracket.
    (                # $1: Square bracket contents.
      [^[\]]*        # {normal*} Zero or more non-[].
      (?:            # Begin {(special normal*)*}.
        \[[^[\]]*\]  # {special} Nested matching [] pair.
        [^[\]]*      # More {normal*} Zero or more non-[].
      )*             # End {(special normal*)*}.
    )                # $1: Square bracket contents.
    \]               # Literal close square bracket.
    (?:              # Optional matching parentheses.
      \(             # Literal open parentheses.
      ([A-Za-z]+)    # $2: Parentheses contents.
      \)             # Literal close parentheses.
    )?               # Optional matching parentheses.
    /x',
    $input,
    $matches);

改进(主要是装饰/风格):

  • 正则表达式包含在'single quotes'而不是"double quotes"中。对于PHP,使用双引号字符串有一个额外的解释级别,还有更多的字符转义序列需要处理(特别是"$"字符会导致恶作剧)。结论:使用PHP,最好将正则表达式模式包含在单引号字符串中(即少了反斜杠汤)。
  • 重新安排与[nested [square bracket] structure]匹配的表达式逻辑,以实现Friedl's“Unrolling-the-Loop”效率技术。对于外方括号没有嵌套方括号的情况,这会导致较少的回溯。
  • 捕获组的开括号和近括号(跨越多行)缩进到同一级别(即垂直对齐),以方便视觉匹配。
  • 捕获组编号包含在带有左括号和右括号的行的注释中。
  • 删除s 单行修饰符(不需要 - 没有点!)。
  • 删除i 忽略大小写修饰符,并将受影响的角色类[a-z]更改为[A-Za-z]以进行补偿。 (在区分大小写模式下,某些正则表达式引擎运行得更快。)
  • 文字"]"结束方括号元字符显式转义,即:"\]"。 (虽然这不是必需的,但恕我直言是好的做法。)
  • 捕获组$2合并到一行。
  • 正则表达式顶部添加了一个全宽标题注释,用于描述整体正则表达目的。

答案 1 :(得分:0)

我认为你只需稍微调整你的第一个正则表达式:

preg_match_all("#\[(.*?)\](?:\(([a-z]+)\))?#is",$html,$matches)
                          ^^^            ^^

这样,带括号的字母是可选的。

修改

鉴于澄清,这是一个新的正则表达式:

\[((?:[^][]|\[[^][]*?\])*?\](?:\(([a-z]+)\))?

这是a Rubular demo