这听起来像个 Jest ,但我可以证明这一点。
假设:
s
匹配时才与s.toUpperCase()
匹配。 以下所有内容都很合乎逻辑,并在Java中成立:
"ffi".matches(".")
拉丁小字体FFI(U + FB03)是字符,因此必须与"ß".matches(".")
拉丁文小写字母SHARP S(U + 00DF)是一个字符,因此必须与Unicode标准的
"ffi".toUpperCase().equals("FFI")
(没有大写字母FFI)"ß".toUpperCase().equals("SS")
(有大写的S,但没有使用)"FfI".toUpperCase().equals("FFI")
显然是"sS".toUpperCase.equals("SS")
显然是因此,假设正则表达式中的第一个点代表
ffi
,第二个点代表ß
,则正则表达式必须匹配“FFISS”,并且由于大小写敏感,因此也匹配“FfIsS”。我确实希望有问题,否则正则表达式将变得非常不可用。
问题:
最佳答案
案例折叠
答案是否定的,点号不会与大小写匹配,尽管原因有些深奥。
但是,最了解此类事情的人常常会引起您的困惑,因为他们也觉得这会导致矛盾。
Unicode中有两种形式的大小写映射。有一种简单的情况映射,其中一个代码点仅映射到另一个代码点。因此,如果使用ss
,那么可以保证也使用length(s) == 1
,其中length(fc(s)) == 1
是Unicode折叠案例图。但它也适用于fc
,uc
和tc
大小写映射。
这样做的问题是,您无法对某些种类的真实文本进行分析得到满意的结果,然后您将做出精确的1:1长度保证。
实际上,其中有很多。数字表示在四种情况图中,多少个单独的BMP代码点映射到指定的长度:
length lc == 2 1
length lc == 3 0
length fc == 2 88
length fc == 3 16
length uc == 2 86
length uc == 3 16
length tc == 2 32
length tc == 3 16
使用全大写而不是Java的正则表达式使用的简单大写,即使长度不相等,确实也可以使
lc
和tschüß
之类的东西匹配。在进行不区分大小写的比较时,Perl和Ruby使用完整的大小写映射。如果您不小心的话,这会在否定的字符类中引起奇怪的悖论。但是有一个难题:不区分大小写的匹配不会执行传递操作。换句话说,如果
TSCHÜSS
匹配.
且在不区分大小写的情况下匹配,则ß
匹配ß
,这并不意味着通过传递性SS
不区分大小写地匹配.
。尽管比我聪明的人对此事已深思熟虑,但这并不是那样的。但是,这两个代码点:
当然,在全大小写映射下,它们不仅区分大小写,而且匹配
SS
,SS
,Ss
和sS
。在简单的案例映射下,他们只是不这样做。Unicode确实对此提供了一些保证。一种是,如果是
ss
,则该length(s) == n
,其中length(fn(s)) <= 3*n
是以下四个案例图中的任意一个:fn
,lc
,fc
和uc
。归一化
如果您认为这很糟糕,那么当您考虑归一化形式时,情况实际上会恶化很多。这里的保证是5倍而不是3倍。因此
tc
,如您所见,它变得越来越昂贵。这是一个等效表,显示在四种规范化形式的每种形式下,有多少个代码点扩展为一个以上:
length NFC == 2 70
length NFC == 3 2
length NFC == 4 0
length NFC == 5 0
length NFKC == 2 686
length NFKC == 3 404
length NFKC == 4 53
length NFKC == 5 15
length NFD == 2 762
length NFD == 3 220
length NFD == 4 36
length NFD == 5 0
length NFKD == 2 1345
length NFKD == 3 642
length NFKD == 4 109
length NFKD == 5 16
那不是很了不起吗?一段时间以来,Unicode希望尝试在其模式匹配中建立规范对等。他们知道,由于上述原因,它很昂贵,但是他们花了一段时间才弄清楚,由于在一个字素单元中对字符进行必要的规范重新排序,从根本上来说是不可能的。
出于这个原因,以及其他许多原因,如果您想“不区分大小写”或“不归一化”地比较事物,当前的建议是自己在两端进行转换,然后比较结果。
例如,给定一个合适的
length(NFx(s)) <= 5 * length(s)
码点对码点等价运算符fc(a) == fc(b)
同样适用于
==
模式匹配运算符(当然,该运算符以传统方式工作,不像Java破损的=~
方法不适当地固定内容):fc(a) =~ fc(b)
这样做的问题是,您不能再在模式的特定部分打开或关闭不区分大小写的功能,例如
/aaa(?i:xxx)bbb/
并且只区分大小写
match
部分。如Perl和Ruby所证明的那样,完整的 shell 很难,但是可以做到(在大多数情况下)。但这在您应该理解的地方也不太直观(读:令人惊讶)。您必须对带括号的字符类进行特殊处理,尤其是对它们的否定,否则会导致废话。
语言环境匹配
最后,要使事情真正复杂,在现实世界中,您需要做的不仅仅是事例映射和规范化中的一个或两个。在某些国家/地区,情况更加复杂。例如,在德语电话簿中,带有变音符的元音与该基本元音后跟字母e的计数完全相同。因此,应该像
xxx
这样区分大小写地匹配müß
。为了做到这一切,您确实不仅需要绑定(bind)完整的案例映射和规范化表,DUCET本身,Default Unicode Collation Element Table甚至是CLDR数据(请参见引用书目):
#!/usr/bin/perl
use utf8;
use open qw(:utf8 :std);
use Unicode::Collate::Locale;
my $Collator = Unicode::Collate::Locale->new(
locale => "de__phonebook",
level => 1,
normalization => undef,
);
my $full = "Ich müß Perl studieren.";
my $sub = "MUESS";
if (my ($pos,$len) = $Collator->index($full, $sub)) {
my $match = substr($full, $pos, $len);
print "Found match of literal ‹$sub› at position $pos in ‹$full› as ‹$match›\n";
}
如果运行该命令,则会发现它确实有效:
Found match of literal ‹MUESS› at position 4 in ‹Ich müß Perl studieren.› as ‹müß›
精选书目
这些示例中的大多数都是在其作者的允许下摘自《 Programming Perl》第4版。 :)我在那里写了很多有关此类Unicode问题的文章,这些不是Perl特有的,但总体来说是Unicode的。
unichars(1)程序,它使我可以收集以下统计信息:
$ unichars 'length fc == 2' | wc -l
88
$ unichars 'length NFKD == 4' | wc -l
109
$ unichars '/ss/i'
U+00DF ß LATIN SMALL LETTER SHARP S
U+1E9E ẞ LATIN CAPITAL LETTER SHARP S
是Unicode::Tussle CPAN模块套件的一部分,Brian Foy非常友好地为我维护。
进一步阅读
也可以看看:
关于java - 假设Unicode和不区分大小写,模式 “..”是否应匹配 “FfIsS”?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19135354/