您可以使用允许对匹配结果应用函数的preg_replace_callback来执行此操作:
$subject = <<<'LOD'
SELECT * FROM UtilisateurApplicatif
WHERE idUtilisateurApplicatif <> "-1"
AND Identification = "TOTO"
AND MotDePasse = "Toto\"TUTU" AND Actif = 1
LOD;
$pattern = <<<'LOD'
~
(?(DEFINE)
(?<DQuotedContent>
(?> [^"\\]++ | (?:\\{2})++ | \\. )*
)
)
" \g<DQuotedContent> " \K | [A-Z]++
~x
LOD;
$result = preg_replace_callback($pattern,
function ($match) { return strtolower($match[0]); },
$subject);
print_r($result);
图案说明:
该模式的想法是匹配之前引用的部分并将它们从匹配结果中删除以不应用strtolower。
首先,我定义了一个子模式 ( DQuotedContent
),其中包含双引号之间的所有可能内容,即:
- 所有不是双引号或反斜杠的字符
[^"\\]
- 所有偶数个反斜杠
(?:\\{2})++
(无法逃脱任何东西)
- 转义字符(转义的双引号不能关闭带引号的字符串)
模式的主要部分现在很容易编写:
" \g<DQuotedContent> " # quoted part
\K # reset all that have been matched before
| # OR
[A-Z]++ # uppercase letters
请注意,\K
它非常有用,因为它从匹配中删除了引用的部分。因此,回调函数不必知道应用strtolower匹配的内容。
注意:为了提高可读性,我使用 nowdoc 语法、定义部分、命名子模式和注释模式 ( ~x
) 编写了模式,但您可以在更紧凑的版本中使用相同的模式:
$pattern = '~"(?>[^"\\\]++|(?:\\\{2})++|\\\.)*"\K|[A-Z]++~';
与 nowdoc 语法不同,反斜杠必须转义两次。