你可以使用这个模式:
$pattern = '~__\((["\'])(?<param1>(?>[^"\'\\\]+|\\\.|(?!\1)["\'])*)\1(?:,\s*(?<param2>\$[a-z0-9_-]+))?\);~si';
if (preg_match_all($pattern, $data, $matches, PREG_SET_ORDER))
print_r($matches);
但正如 Jon 所注意到的,这种模式可能难以维护。这就是为什么,我建议将模式更改为:
$pattern = <<<'LOD'
~
## definitions
(?(DEFINE)
(?<sqc> # content between single quotes
(?> [^'\\]+ | \\. )* #'
# can be written in a more efficient way, with an unrolled pattern:
# [^'\\]*+ (?:\\. ['\\]*)*+
)
(?<dqc> # content between double quotes
(?> [^"\\]+ | \\. )* #"
)
(?<var> # variable
\$ [a-zA-Z0-9_-]+
)
)
## main pattern
__\(
(?| " (?<param1> \g<dqc> ) " | ' (?<param1> \g<sqc> ) ' )
# note that once you define a named group in the first branch in a branch reset
# group, you don't have to include the name in other branches:
# (?| " (?<param1> \g<dgc>) " | ' ( \g<sqc> ) ' ) does the same. Even if the
# second branch succeeds, the capture group will be named as in the first branch.
# Only the order of groups is taken in account.
(?:, \s* (?<param2> \g<var> ) )?
\);
~xs
LOD;
这个简单的更改使您的模式更具可读性和可编辑性。
引号之间的内容 子模式旨在处理转义的引号。这个想法是匹配所有前面有反斜杠的字符(可以是反斜杠本身),以确保匹配文字反斜杠和转义引号::
\' # an escaped quote
\\' #'# an escaped backslash and a quote
\\\' # an escaped backslash and an escaped quote
\\\\' #'# two escaped backslashes and a quote
...
子模式详情:
(?> # open an atomic group (inside which the bactracking is forbiden)
[^'\\]+ #'# all that is not a quote or a backslash
| # OR
\\. # an escaped character
)* # repeat the group zero or more times