【问题标题】:Regex to remove outer brackets正则表达式删除外括号
【发布时间】:2012-05-26 12:53:29
【问题描述】:

我一直在使用这个 /\(\s*([^)]+?)\s*\)/ 正则表达式通过 PHP preg_replace 函数删除外括号(在我的上一个问题 Regex to match any character except trailing spaces 中阅读更多信息)。

这在只有一对括号时可以正常工作,但问题是当有更多括号时,例如( test1 t3() test2) 变为test1 t3( test2) 而不是test1 t3() test2

我知道正则表达式的限制,但如果有一对以上的括号,我可以让它不匹配任何东西。

所以,示例行为就足够了:

( test1 test2 ) => test1 test2

( test1 t3() test2 ) => (test1 t3() test2)

编辑:

我想继续修剪已删除括号内的尾随空格。

【问题讨论】:

  • 您应该在示例中添加尾随空格并说明您不想要它。否则,当您意识到您接受的解决方案不适用于尾随空格时,您将不得不提出第三个问题:P
  • 我编辑了示例,这样人们就可以通过尝试示例来查看他们的代码是否满足该要求。有内括号,为什么还要保留外括号?
  • 因为这个正则表达式只是更大的一部分,我只是想保持简单并要求这个括号部分。如果之前/之后有括号,则删除括号会使输出字符串在语法上无效。

标签: php regex preg-replace brackets


【解决方案1】:

您可以使用这种基于递归正则表达式的代码,该代码也适用于嵌套括号。唯一的条件是括号应该是平衡的。

$arr = array('Foo ( test1 test2 )', 'Bar ( test1 t3() test2 )', 'Baz ((("Fdsfds")))');
foreach($arr as $str)
   echo "'$str' => " . 
         preg_replace('/ \( \s* ( ( [^()]*? | (?R) )* ) \s* \) /x', '$1', $str) . "\n";

输出:

'Foo ( test1 test2 )' => 'Foo test1 test2'
'Bar ( test1 t3() test2 )' => 'Bar test1 t3() test2'
'Baz ((("Fdsfds")))' => 'Baz (("Fdsfds"))'

【讨论】:

  • 哇,这很有趣。你能解释一下| (?R) 部分吗?可以应用多线/米吗?另请注意,对于( test1 t3() test2 ),它会留下尾随空格。谢谢。
  • 这里有一个很棒的 PHP 递归正则表达式教程:asiteaboutnothing.net/regexp/regex-recursion.html,它也可以与 /m 一起工作。几个小时后,当我到达我的计算机时,我将修改正则表达式以删除尾随空格。
  • 谢谢,我正在阅读。我不确定为什么它在末尾有 \s* 时不删除尾随空格。一个问题,是否可以只对正则表达式的一部分应用递归,而不是从一开始,所以我可以匹配keyword ( test1 t3() test2 ) => keyword test1 t3() test2
  • @umpirsky:请检查编辑后的答案。它不再留下尾随空格,您可以看到'Bar ( test1 t3() test2 )' => 'Bar test1 t3() test2' 括号前的关键字也被保留。
【解决方案2】:

试试这个

$result = preg_replace('/\(([^)(]+)\)/', '$1', $subject);

更新

\(([^\)\(]+)\)(?=[^\(]+\()

正则表达式解释

"
\(            # Match the character “(” literally
(             # Match the regular expression below and capture its match into backreference number 1
   [^\)\(]       # Match a single character NOT present in the list below
                    # A ) character
                    # A ( character
      +             # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\)            # Match the character “)” literally
(?=           # Assert that the regex below can be matched, starting at this position (positive lookahead)
   [^\(]         # Match any character that is NOT a ( character
      +             # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
   \(            # Match the character “(” literally
)
"

【讨论】:

  • 对于( test1 t3(t4) test2),它返回( test1 t3t4 test2)。谢谢。
  • 这没关系,但缺少我在这个问题中没有提到的一件事,但正在使用我原来的正则表达式 /(\s*([^)]+?)\s* )/ 这就是在删除的括号内修剪尾随空格。
【解决方案3】:

你可能想要这个(我猜这就是你最初想要的):

$result = preg_replace('/\(\s*(.+)\s*\)/', '$1', $subject);

这会得到

"(test1 test2)" => "test1 test2"
"(test1 t3() test2)" => "test1 t3() test2"
"( test1 t3(t4) test2)" => "test1 t3(t4) test2"

【讨论】:

  • 我认为 OP 喜欢在最后两种情况下保留括号。
  • @Cylian OP 说“我知道正则表达式的限制,但是如果我可以让它不匹配任何东西,如果有一对以上的括号,那就太好了。”所以我想如果我正确理解他的“更好”需求会更好。如果 OP 在看到这个答案后仍然想保留它们,我会自己删除它:-P
  • 我对这两种解决方案都感兴趣。这没关系,但是缺少我在这个问题中没有提到的一件事,但是正在使用我的原始正则表达式 /\(\s*([^)]+?)\s*\)/ 并且正在修剪删除的括号内的尾随空格。
  • @umpirsky 这个确实会修剪尾随空格,如您所见,我已经更新了答案以添加一些引号。
  • 对于( test1 test2 ),它返回test1 test2 。请注意末尾有空格。谢谢。
猜你喜欢
  • 1970-01-01
  • 2020-02-14
  • 2018-08-25
  • 1970-01-01
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多