Php 在另一个捕获中捕获可选组
给定输入Php 在另一个捕获中捕获可选组,php,regex,regex-group,Php,Regex,Regex Group,给定输入 ${first_name}, ${last_name}, ${create_date:(Y-m-d)}, ${submit_date:(Y-m-d)} 我可以使用\${(.*)}捕获括号中的所有内容。当后缀出现在示例中的日期上时,我想将其作为自己的组捕获。如何使用一个正则表达式实现这一点?您可以试试这个 \$\{([^:, ]*(?::\(([^)]*)\))?)\} ,其中curely brace内的总值(字符串)被捕获到组1,可选值(字符串)被捕获到组2 如果你不想在组1和组2
${first_name}, ${last_name}, ${create_date:(Y-m-d)}, ${submit_date:(Y-m-d)}
我可以使用\${(.*)}
捕获括号中的所有内容。当后缀出现在示例中的日期上时,我想将其作为自己的组捕获。如何使用一个正则表达式实现这一点?您可以试试这个
\$\{([^:, ]*(?::\(([^)]*)\))?)\}
,其中curely brace内的总值(字符串)被捕获到组1
,可选值(字符串)被捕获到组2
如果你不想在组1和组2之间建立包容关系,你也可以试试这个
\$\{([^:, ]*)(?::\(([^)]*)\))?\}
我认为您最初的方法
\${(.*)}
有一个小问题,即您的通配符*
包含您不想匹配的}
符号。事实上,一旦您开始捕获,这是您唯一不想匹配的内容,因此我们会更改:
.* // match anything zero or more times
到
但是,您希望匹配大括号内的所有内容,除非它具有结构某些带下划线的单词:(所需文本)
,在这种情况下,您希望匹配所需文本
我可以通过使用?
操作符来解决这个问题,您可以将它放在捕获组之后,将其定义为可选的。?
是贪婪的,这意味着它将首先尝试匹配,并且只有当它失败时,才会尝试在没有可选模式的情况下处理匹配
考虑到这一点,用贪婪的思维来重新表述你想要的东西是有帮助的
而不是说:
我想捕捉花括号里面的任何东西
捕获括号内的值(如果存在)
将其更改为:
我想捕获嵌套在括号内的值
在花括号里,但如果不存在的话,我就
不管支架里有什么
将其转换为正则表达式,我得到:
\${([a-z_]+:\()?([^\)}]*)
细分:
首先查找唯一的符号:
${
尝试与嵌套模式匹配:
([a-z_]+:\()?
这会匹配任何带下划线的小写单词一次或多次(+
),后跟:(
现在,我们匹配零个或多个不是结束标记的字母)
或}
([^\)}]*)
由于贪婪,它会直接使用嵌套模式。如果做不到这一点,匹配将退回到捕获任何不是结束符号的内容
我能想到的一个不可行的情况是:
${seems like a normal match) wait where did these letters go?}
这将使您“看起来像是一个正常的匹配”。要构建最佳/最快的模式,您需要允许正则表达式引擎以贪婪的方式尽可能多地执行,这意味着使用诸如*
和+
之类的量词,而不带尾随?
以下模式需要第一个捕获组(输出列[1]
),并使第二个捕获组可选(输出列[2]
)
建议的模式:~\$\{([^:}]+)(?::([^}]+)?~
()
代码:()
您可以忽略[0]
(fullstring)匹配列。您只对第一个和第二个捕获组感兴趣
输出:
array (
0 =>
array (
0 => '${first_name',
1 => 'first_name',
),
1 =>
array (
0 => '${last_name',
1 => 'last_name',
),
2 =>
array (
0 => '${create_date:(Y-m-d)',
1 => 'create_date',
2 => '(Y-m-d)',
),
3 =>
array (
0 => '${submit_date:(Y-m-d)',
1 => 'submit_date',
2 => '(Y-m-d)',
),
)
您是否可以显示您的代码并明确您希望从示例字符串中得到的结果。示例中的某物
在哪里?\$\{(.*?)}
将已经捕获到该结果。或者你的意思是分别捕获“键/值”\$\{(.*?(:(.*?))\}
?是的@NiettheDarkAbsol,这正是我想要的。非常感谢。
~ #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');
array (
0 =>
array (
0 => '${first_name',
1 => 'first_name',
),
1 =>
array (
0 => '${last_name',
1 => 'last_name',
),
2 =>
array (
0 => '${create_date:(Y-m-d)',
1 => 'create_date',
2 => '(Y-m-d)',
),
3 =>
array (
0 => '${submit_date:(Y-m-d)',
1 => 'submit_date',
2 => '(Y-m-d)',
),
)