给出像
这样的输入${first_name}, ${last_name}, ${create_date:(Y-m-d)}, ${submit_date:(Y-m-d)}
我可以使用\${(.*)}
来捕捉括号之间的所有内容。当后缀出现在示例中的日期时,我想将其捕获为自己的组。我怎么能用一个正则表达式做到这一点?
答案 0 :(得分:0)
你可以试试这个,
\$\{([^:, ]*(?::\(([^)]*)\))?)\}
Demo ,,,其中curely-brace内的总值(字符串)被捕获到group 1
,可选值(字符串)被捕获到group 2
。
如果你不想要第1组和第2组之间的包容性关系,你也可以试试这个,
\$\{([^:, ]*)(?::\(([^)]*)\))?\}
答案 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]