捕获另一个捕获中的可选组

时间:2018-04-27 15:20:31

标签: php regex regex-group

给出像

这样的输入
${first_name}, ${last_name}, ${create_date:(Y-m-d)}, ${submit_date:(Y-m-d)}

我可以使用\${(.*)}来捕捉括号之间的所有内容。当后缀出现在示例中的日期时,我想将其捕获为自己的组。我怎么能用一个正则表达式做到这一点?

3 个答案:

答案 0 :(得分:0)

你可以试试这个,

\$\{([^:, ]*(?::\(([^)]*)\))?)\}

Demo ,,,其中curely-brace内的总值(字符串)被捕获到group 1,可选值(字符串)被捕获到group 2

如果你不想要第1组和第2组之间的包容性关系,你也可以试试这个,

\$\{([^:, ]*)(?::\(([^)]*)\))?\}

Demo

答案 1 :(得分:0)

我认为您的原始方法\${(.*)}存在一个小问题,即您的通配符匹配器.*包含您不想匹配的}符号。事实上,一旦你开始捕捉它,你唯一想要匹配的东西,所以我们改变了:

.*      // match anything zero or more times

[^}]*   // match anything that isn't } zero or more times

但是你想要匹配大括号内的所有内容,除非它有结构some_underscored_words:(desired-text),在这种情况下你要匹配desired-text

我通过使用?运算符来解决这个问题,运算符放在捕获组之后将其定义为可选。 ?是贪婪的,这意味着它会先尝试匹配,只有当它失败时才会尝试处理没有可选模式的匹配。

考虑到这一点,使用贪心思维来改写你想要的东西是有帮助的。

而不是说:

  

我想捕捉花括号里面的任何东西   如果它们存在,则捕获括号内的值

将其更改为:

  

我想捕获嵌套在括号内的值   在花括号内,但如果那不存在,我就会有   无论什么都在大括号内。

把它变成一个正则表达式,我明白了:

\${([a-z_]+:\()?([^\)}]*)

打破它:

首先寻找独特的符号:

${

尝试匹配嵌套模式:

([a-z_]+:\()?

这匹配any_underscored_lowercase_words一次或多次(+)后跟:(

现在我们匹配的零个或多个字母不是我们的结束标记)}

([^\)}]*)

贪婪,直接进入嵌套模式。如果做不到这一点,那么这场比赛将回归到捕捉任何不是任何一个结束符号的东西。

我能想到的一个方案就是:

${seems like a normal match) wait where did these letters go?}

这会给你"看起来像是一场正常的比赛"。

答案 2 :(得分:0)

要构建最佳/最快的模式,您需要允许正则表达式引擎尽可能以贪婪的方式执行,这意味着使用*+之类的量词,而不是尾随{{1} }。

以下模式将需要第一个捕获组(输出列?)并使第二个捕获组可选(输出列[1])。

建议模式:[2]Pattern Demo

~\$\{([^:}]+)(?::([^}]+))?~

代码:(Demo

~             #starting pattern delimiter
\$\{          #match a dollar sign then opening curly bracket
(             #start Capture Group #1
  [^:}]+      #match one or more non-colon, non-closing curly bracket characters
)             #end Capture Group #1
(?:           #start non-capturing group
  :           #match a colon
  (           #start Capture Group #2
    [^}]+     #match one or more non-closing curly brackets
  )           #end Capture Group #2
)?            #end non-capturing group and allow zero or one occurence of the group
~             #end pattern delimiter

您可以忽略$string = '${first_name}, ${last_name}, ${create_date:(Y-m-d)}, ${submit_date:(Y-m-d)}'; var_export(preg_match_all('~\$\{([^:}]+)(?::([^}]+))?~', $string, $out, PREG_SET_ORDER) ? $out : 'fail'); (全字符串)匹配列。您只对第一个和第二个捕获组感兴趣。

输出:

[0]