“st” 可以用一个字符的
风格连字 表示为
st
或
ſt
,因此它的长度可以是 2 或 1。
使用 bash 命令快速查找 Perl 的完整 2→1 字符连字列表:
$ perl -e 'print $^V'
v5.26.2
$ for lig in {a..z}{a..z}; do \
perl -e 'print if /(?<!'$lig')x/i' 2>/dev/null || echo $lig; done
ff fi fl ss st
这些分别代表着连字体中的
ff
、
fi
、
fl
、
ß
和
st
/
ſt
。(
ſt
代表使用过时的
长s字符的
ſt
;它与
st
匹配,而不匹配
ft
。)
Perl还支持剩余的样式连字体
ffi
和
ffl
用于
ffi
和
ffl
,但在这种情况下这并不值得注意,因为回顾先行断言已经单独处理了
ff
和
fi
/
fl
的问题。
未来版本的Perl可能会包括更多的字体连字,尽管现在仍然是特定于字体的(例如
Linux Libertine具有
ct
和
ch
的字体连字),或者是有争议的风格(例如荷兰语中用于
ij
的
ij
或西班牙语中废弃的
ꝇ
代替
ll
)。对于不完全可互换的连字,似乎没有必要使用这种处理方式(例如没有人会接受
dœs
代替
does
),但也有其他情况,例如包括
ß
,因为它的
大写形式是SS
。
Perl 5.16.3(以及类似的旧版本)只能识别“ss”(表示“ß”),不能扩展后瞻中的其他连字号(它们具有固定宽度,因此不会匹配)。我没有寻找修复错误的细节,以列出受影响的确切版本。
Perl 5.14引入了连字号支持,因此早期版本没有这个问题。
解决方法:
对于“/(?<!August)x/i”(只有第一个可以正确避免“August”)的解决方法:
/(?<!Augus[t])(?<!Augu(?=st).)x/i
(绝对全面)
/(?<!Augu(?aa:st))x/i
(仅在回顾中的st
是“ASCII安全”的²)
/(?<!(?aa)August)x/i
(整个回顾都是“ASCII安全”的²)
/(?<!August)x/iaa
(整个正则表达式都是“ASCII安全”的²)
/(?<!Augus[t])x/i
(破坏连字寻找¹)
/(?<!Augus.)x/i
(稍微不同,匹配更多)
/(?<!Augu(?-i:st))x/i
(回顾中区分大小写的st
,不会匹配AugusTx
)
这些操作玩具通常涉及移除大小写敏感修饰符¹或添加ASCII安全修饰符²到不同的位置,经常需要正则表达式编写者明确知道变宽连字。
第一个变体(也是唯一全面的)通过两个回顾后方匹配可变宽度:首先是六个字符版本(如下面第一个引用中所述没有连字),其次是任何连字,采用前瞻(它的宽度为零!)来匹配
st
(包括连字),然后使用
.
考虑其单个字符宽度。
perlre
man page的两个部分:
¹ 大小写不敏感修饰符/i
和连字
There are a number of Unicode characters that match a sequence of
multiple characters under /i
. For example, "LATIN SMALL LIGATURE
FI" should match the sequence fi
. Perl is not currently able to
do this when the multiple characters are in the pattern and are
split between groupings, or when one or more are quantified. Thus
"\N{LATIN SMALL LIGATURE FI}" =~ /fi/i;
"\N{LATIN SMALL LIGATURE FI}" =~ /[fi][fi]/i;
"\N{LATIN SMALL LIGATURE FI}" =~ /fi*/i;
"\N{LATIN SMALL LIGATURE FI}" =~ /(f)(i)/i;
² ASCII安全修改器 /aa
(perl 5.14+)
禁止ASCII/非ASCII匹配(例如,k
和 \N{KELVIN SIGN}
),
需要两次指定a
,例如/aai
或/aia
。(第一个
出现的a
限制了\d
等,第二个出现的a
添加了/i
的限制。)但是,需要注意的是,ASCII范围之外的代码点将使用Unicode规则进行/i
匹配,因此该修改器
实际上并不仅限于ASCII;它只禁止混合使用ASCII和非ASCII。
总之,这个修改器为不希望暴露于整个Unicode的应用提供保护。指定两次会增加保护。
/(?<!August )a/i
已经表明了“可变长度后顾断言”...但是如果从August
中删除一个字母,它就能正常工作。删除/i
也能正常工作。如果你想笑的话:August
不起作用,如上所示。Abcdst
不起作用。但是Abcdet
起作用。 - Dadast
可以作为连字符存在?同样的,fi
和ff
也是。 - chorobapod/perl5220deltapod
提到了“正则表达式m/%s/中未实现可变长度回溯”的警告。因此,我猜测5.22.0版本已经非常接近了,并且该警告的perldiag条目已添加有关Unicode行为的信息。 - sticky bit