首页 > 解决方案 > preg_match - 忽略可选括号

问题描述

我有以下字符串,其中包含与preg_match. 键是输入,值是预期输出:

$strings = [
  '(prefix) (string in parens)'   => 'string in parens',
  '(prefix) string not in parens' => 'string not in parens',
  '(prefix) parens (at the end)'  => 'parens (at the end)',
];

假设我想在单个 中执行此操作preg_match,我目前有以下内容:

preg_match('/^\(prefix\) (\((.+)\)|.+)$/', $input, $matches);
$output = (isset($matches[2]) ? $matches[2] : $matches[1]);

这可行,但需要一个单独的子模式来检测看到的格式。有没有更好的方法在单个子模式中做到这一点?在子模式的任一端假设可选括号是不够的,因为我可能想包含括号。

我知道我还有其他选项,例如分别剥离前缀和括号,但我想知道是否有更好的方法来做到这一点而无需先改变逻辑。

标签: phpregexpreg-match

解决方案


在单个捕获组中获取所有匹配项的一种选择是使用分支重置组在从左括号到右括号的前缀之后捕获,或者在没有括号但仅可选地在末尾匹配它的行之后捕获。

^\(prefix\)\h(?|\(([^()\n]+)\)|([^()\n]+(?:\([^()\n]+\))?))$
  • ^字符串的开始
  • \(prefix\)\h匹配(prefix)和水平空白字符
  • (?|分支重置组
    • \(([^()\n]+)\)(直接从...匹配)并在第 1 组中捕获介于两者之间的内容
    • |或者
    • (捕获组 2
      • [^()\n]+匹配除( )换行符以外的任何字符
      • (?:\([^()\n]+\))?可选匹配(...)
    • )关闭组 2
  • )关闭分支重置组
  • $字符串结束

正则表达式演示

或者正如您所指出的,这种模式^\(prefix\) (?|\((.+)\)|(.+))$将是一种广泛匹配,可以捕获括号之间的内容或后面的所有内容。


推荐阅读