【问题标题】:PHP: regex to match complete matching brackets?PHP:正则表达式匹配完整的匹配括号?
【发布时间】:2013-02-05 18:46:59
【问题描述】:

在 PHP 中,我有以下字符串:

 $text = "test 1
          {blabla:database{test}}
          {blabla:testing}
          {option:first{A}.Value}{blabla}{option:second{B}.Value}
          {option:third{C}.Value}{option:fourth{D}}
          {option:fifth}
          test 2
         ";

我需要从这个字符串中取出所有的 {option...}(这个字符串中总共 5 个)。有些有多个嵌套括号,有些则没有。有些在同一行,有些不在。

我已经找到了这个正则表达式:

(\{(?>[^{}]+|(?1))*\})

所以以下工作正常:

preg_match_all('/(\{(?>[^{}]+|(?1))*\})/imsx', $text, $matches);

不在大括号内的文本被过滤掉,但匹配项还包括我不需要的blabla-items。

有什么方法可以将此正则表达式更改为仅包含option-items?

【问题讨论】:

  • 这听起来像是语法解析器的工作。我曾经遇到过一个相关的问题。我很好奇是否有人会做这项工作! :)
  • 可以嵌套多少个大括号?
  • 我几乎因为提出类似问题而被禁止。只是我似乎在观众面前运气不好。无论如何,我不是通过正则表达式,而是通过stack-based parentheses match 循环解决了它。只是作为一种选择。

标签: php regex nested


【解决方案1】:

这个问题更适合合适的解析器,但是如果你真的想的话,你可以用正则表达式来解决。

只要您没有在其他选项中嵌入选项,这应该可以工作。

preg_match_all(
    '/{option:((?:(?!{option:).)*)}/',
    $text,
    $matches,
    PREG_SET_ORDER
);

快速解释。

{option:               // literal "{option:"
  (                    // begin capturing group
    (?:                // don't capture the next bit
      (?!{option:).    // everything NOT literal "{option:"
    )*                 // zero or more times
  )                    // end capture group
}                      // literal closing brace

var_dumped 输出与您的示例输入如下所示:

array(5) {
  [0]=>
  array(2) {
    [0]=>
    string(23) "{option:first{A}.Value}"
    [1]=>
    string(14) "first{A}.Value"
  }
  [1]=>
  array(2) {
    [0]=>
    string(24) "{option:second{B}.Value}"
    [1]=>
    string(15) "second{B}.Value"
  }
  [2]=>
  array(2) {
    [0]=>
    string(23) "{option:third{C}.Value}"
    [1]=>
    string(14) "third{C}.Value"
  }
  [3]=>
  array(2) {
    [0]=>
    string(18) "{option:fourth{D}}"
    [1]=>
    string(9) "fourth{D}"
  }
  [4]=>
  array(2) {
    [0]=>
    string(14) "{option:fifth}"
    [1]=>
    string(5) "fifth"
  }
}

【讨论】:

  • 嗨,Leigh,一个小问题仍然存在:如果两个选项之间有 {...},那么 {...} 部分会包含在匹配中。 (参见修改后的示例文本)有什么方法可以避免这种情况?
  • @Dylan 可以使用递归来完成。请参阅我最初在 cmets 中链接到您的问题的答案。你应该能够适应它。
【解决方案2】:

试试这个正则表达式 - 它是使用 .NET 正则表达式测试的,它也可以与 PHP 一起使用:

\{option:.*?{\w}.*?}

请注意 - 我假设您只有 1 对括号内,并且在该对内您只有 1 个字母数字字符

【讨论】:

    【解决方案3】:

    我修改了您的初始表达式以搜索附加了非空白字符 (\S*) 的字符串“(option:)”,并以花括号“{}”为界。

    \{(option:)\S*\}
    

    根据您的输入文本,以下条目在正则表达式中匹配:

    测试 1

    {blabla:数据库{测试}}

    {blabla:testing}

    {option:first{A}.Value} {option:second{B}.Value}

    {option:third{C}.Value}

    {option:fourth{D}}

    {option:fifth}

    测试 2

    【讨论】:

    • 工作正常,但是当 A 和 B 选项之间没有空格时,Leigh 的答案也有效,所以我选择了那个作为答案。
    【解决方案4】:

    如果您在同一级别上没有多对括号,这应该可以工作

    /(\{option:(([^{]*(\{(?>[^{}]+|(?4))*\})[^}]*)|([^{}]+))\})/imsx
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      • 2020-05-04
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 2015-10-24
      相关资源
      最近更新 更多