你可以试试这个:
$subject = '15 + func1 ("gis", 22, func (55), 87) + 95 + func2 () + 35';
$pattern = <<<'LOD'
~
#definitions:
(?(DEFINE)(?<int> [0-9]++ ))
(?(DEFINE)(?<str> "[^"]++" ))
(?(DEFINE)(?<f_name> \b[a-z]\w*+\b ))
(?(DEFINE)(?<sep> ,\h ))
#pattern:
(?=
(
(?<func>\g<f_name>) \s*+
\(
(?<args>
(?> (?> \g<int> | \g<str> | (?-3) ) \g<sep>?+ )*
)
\)
)
)
~x
LOD;
preg_match_all($pattern, $subject, $matches);
print_r($matches['func']);
print_r($matches['args']);
这个想法是使用递归来匹配函数内部的函数,并将所有模式放在一个前瞻中以捕获所有重叠的参数。
请注意,我使用递归(?-3)
来引用左侧的第三个捕获组,这是模式的第一组,因此您可以将其替换为(?1)
. 但是,如果您想将此模式用作子模式,则相对引用可能很有用。
与(?(DEFINE)..)
注释模式(x 修饰符)结合使用可能很有用,因为它是高度可编辑的,您可以添加或编辑数据类型或解析器可能遇到的其他元素。例如,如果您想允许单引号之间的字符串,您可以<str>
像这样更改子模式:
(?(DEFINE)(?<str> "[^"]++" | '[^']++' ))
或者像这样更宽容(允许转义引号):
(?(DEFINE)(?<str> "(?>[^"]++|(?<=\\)")++" | '(?>[^']++|(?<=\\)')++' ))