【问题标题】:preg_match - ignore optional parenthesespreg_match - 忽略可选括号
【发布时间】:2020-08-10 16:34:13
【问题描述】:

我有以下字符串,其中包含与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]);

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

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

【问题讨论】:

    标签: php regex preg-match


    【解决方案1】:

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

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

    Regex demo

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

    【讨论】:

    • 啊哈,看来分支重置组正是我所追求的。我知道我的正则表达式非常松散,但为了避免它看起来像你的答案的巨大飞跃,^\(prefix\) (?|\((.+)\)|(.+))$ 将是一个很好的例子。
    • @cmbuckley 是的,您也可以将其用作匹配项,这取决于您希望模式的具体程度。使用.+ 确实是一个非常广泛的匹配项。
    • 当然,我同意 - 我想更多地展示可能的最小变化,以供其他可能阅读该问题的人使用。
    猜你喜欢
    • 2011-05-31
    • 2018-07-19
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 2011-10-01
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多