【发布时间】:2021-11-21 20:38:53
【问题描述】:
背景/简介
一般来说,PHP 中的正则表达式,例如对于preg_match(),以/ 之类的分隔符开始和结束。我个人经常使用@。
除了分隔符之外,还可以使用 ()、{} 或 [] 等开括号和右括号。
分隔符 char 需要被转义,当它应该被解释为常规字符时。例如。 preg_match('@^\w+\@\w+\.\w+$@', $mail) 需要将'@' 转义为'\@'。
函数preg_quote(string $str, ?string $delimiter) 接受null 作为$delimiter,这表明正则表达式可以以我们不必担心分隔符的方式编写。
使用() 似乎我们不必担心分隔符,因为无论如何'(' 和')' 已经需要转义了。
[] 和 {} 有点不同。虽然孤立的 '[' 会导致错误,但孤立的 ']'、'{' 或 '}' 不会。
动机
对于包开发,我想提供用户可以指定正则表达式片段的方法,而不用担心分隔符的选择。
例如如果我在内部使用'/' 作为分隔符,那么用户(调用代码)需要在提供的正则表达式片段中转义'/'。如果我使用'@',他们可以不转义'/',但需要转义'@'。如果我使用null / '()',他们就不需要逃避任何事情——我想。
这是一个虚构的例子。请不要问->setFragment()是做什么的,你只需要知道第二个参数接收一个正则表达式片段(即可以插入一个正则表达式的sn-p)。
// If regex like '/../':
$system->setFragment('email', '\w+@\w+\.\w+'); // nothing escaped.
$system->setFragment('dir', '\w+(\/\w+)*'); // '/' escaped.
// If regex like '@..@':
$system->setFragment('email', '\w+\@\w+\.\w+'); // '@' escaped.
$system->setFragment('dir', '\w+(/\w+)*'); // nothing escaped.
// If regex like '(..)':
$system->setFragment('email', '\w+@\w+\.\w+'); // nothing escaped.
$system->setFragment('dir', '\w+(/\w+)*'); // nothing escaped.
另一个例子,更类似于我实际在做的事情:
function buildMessageRegex(string $message, ?string $delimiter, array $regex_fragments = []): string {
$quoted_message = preg_quote($message, $delimiter);
$regex_body = strtr($quoted_message, $replacements);
return $delimiter !== null
? $delimiter . '^' . $regex_body . '$' . $delimiter
: '(^' . $regex_body . '$)';
}
// By using $delimiter === null, we don't have to escape '/' or '@'.
$regex = buildMessageRegex('Mail: %mail, Dir: %dir.', null, [
'%mail' => '\w+@\w+\.\w+',
'%dir' => '\w+(/\w+)*',
]);
问题
似乎() 是编写正则表达式的唯一方法,我不必担心分隔符,并且可以使用 null 作为分隔符调用preg_quote($str, null)。
这个假设正确吗?
如果是这样,我总是可以使用() 作为分隔符,并且不需要在方法中提供分隔符选项。
还是我错过了什么?
范围
我不确定这个问题/问题是否特定于 PHP,或者更普遍地适用于 PCRE 任何使用它的地方(我假设是在 Perl 中?)。
我个人对 PHP 案例很感兴趣,但我认为值得在一个很好的答案中提及这在 PHP 之外是如何应用的。
【问题讨论】:
-
你为什么打电话给
preg_quote()?如果用户提供正则表达式片段,不应该将特殊字符保留在其中吗?如果用户输入应按字面意思匹配,而不是正则表达式,则仅使用preg_quote()。 -
如果用户不提供分隔符,这意味着您要添加自己的分隔符。因此,无论您使用什么分隔符,在调用
preg_quote()时都可以使用相同的分隔符。我不明白你为什么关心null案子。 -
我没有在用户提供的正则表达式片段上调用
preg_quote()。对于正则表达式的其他部分,我可能会在流程的其他部分调用它。我只提到它是为了表明 php 确实支持不需要转义分隔符的正则表达式。 -
@Barmar 我在“动机”中添加了一个示例。
-
没关系,现在我看到你在中间逃脱了
@。