典型的用例是当正则表达式需要包含用户输入时。正则表达式中具有特殊含义的字符(即 Perl 中的“脏打”)需要转义。Perl 提供了“quotemeta”功能来做到这一点:只需将插值变量封装在\Q
and中\E
。但是 Tcl 没有提供这样的功能(根据这个页面,即使是 ARE)。
在 Tcl 中是否有一个好的(严格的)quotemeta 实现?
Perl 的quotemeta
函数只是用反斜杠替换每个非单词字符(即,除了 26 个小写字母、26 个大写字母、10 个数字和下划线以外的字符)。这是矫枉过正,因为并非所有非单词字符都是正则表达式元字符,但它简单且安全,因为转义不需要转义的非单词字符是无害的。
我相信这个实现是正确的:
proc quotemeta {str} {
regsub -all -- {[^a-zA-Z0-9_]} $str {\\&} str
return $str
}
但是由于 glenn 的评论,这个更好,至少对于现代版本的 Tcl (\W
匹配任何在 Tcl 8.0.5 之后的某个时间开始的非单词字符):
proc quotemeta {str} {
regsub -all -- {\W} $str {\\&} str
return $str
}
(我假设 Tcl 的正则表达式与 Perl 的足够相似,因此这将在 Tcl 中完成与在 Perl 中相同的工作。)
我会提出一个解决方案,但我不确定它是否正确。
#
# notes
#
# - "[]" has to appear in the beginning of a character class
# - "-" has to come last in a character class
# - "#" is not special, but anticipating the x modifier...
# - "-" is not special, but anticipating interpolation within "[]"...
# - "/" is not special in Tcl
#
proc quotemeta {str} {
regsub -all -- {[][#$^*()+{}\|.?-]} $str {\\\0} str
return $str
}