关于案例折叠
答案是否定的,点不会不区分大小写,尽管原因有点深奥。ss
然而,你的困惑经常被一些最了解这些事情的人提出,因为他们也觉得这会导致矛盾。
Unicode 中有两种形式的案例映射。有一个简单的案例映射,其中一个代码点只映射到另一个代码点。因此,如果 ,那么可以保证,Unicode 折叠映射在哪里。但它也适用于 、 和 事例映射。length(s) == 1
length(fc(s)) == 1
fc
uc
tc
lc
问题在于,在分析某些类型的现实世界文本时,您不会获得那么好的结果,然后您就会做出这些确切的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的正则表达式使用的简单大小写中,您确实可以获得类似和匹配的东西,即使它们的长度不等。Perl 和 Ruby 在进行不区分大小写的比较时使用完整的大小写映射。如果你不小心,这会导致否定字符类中的奇怪悖论。tschüß
TSCHÜSS
但问题是:不区分大小写的匹配不执行传递操作。换句话说,如果匹配且在大小写不敏感匹配下匹配 匹配 ,这并不意味着通过传递性不区分大小写匹配。它只是不以这种方式工作,尽管比我聪明的人已经深入思考了这个问题。.
ß
ß
SS
.
SS
但是,这两个代码点:
- U+00DF ß LATIN SMALL LETTER SHARP S
- U+1E9E ẞ LATIN CAPITAL LETTER SHARP S
当然,不区分大小写不仅彼此匹配,而且 、 、 和 完整大小写映射。他们只是在简单的案例映射下不这样做。SS
Ss
sS
ss
Unicode确实对此做出了一些保证。一个是 if ,那么 where 是四个案例映射中的任何一个:、 、 和 。length(s) == n
length(fn(s)) <= 3*n
fn
lc
fc
uc
tc
关于规范化
如果你认为这是不好的,那么当你考虑规范化形式时,它实际上会变得更糟。这里的保证是5×而不是3×。所以,正如你所看到的,它变得越来越昂贵。length(NFx(s)) <= 5 * length(s)
下面是等效的表,显示四种规范化形式中每种形式的代码点扩展到多个代码点的数量:
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想要尝试在其模式匹配中构建规范等价性。他们知道由于上述原因,这很昂贵,但是他们花了一段时间才弄清楚,由于在一个字形单位内组合字符的必要规范重新排序,这基本上是不可能的。
出于这个原因,以及许多其他原因,如果您想“不区分大小写”或“规范化不敏感地”比较事物,目前的建议是自己通过两边的转换来运行它,然后比较结果。
例如,给定一个合适的代码点逐个代码点等价运算符==
fc(a) == fc(b)
对于模式匹配运算符也是如此(当然,它以传统方式工作,不像Java的破碎方法不恰当地锚定事物):=~
match
fc(a) =~ fc(b)
这样做的问题是,您无法再在模式的特定部分打开或关闭不区分大小写,例如
/aaa(?i:xxx)bbb/
并且只对部分进行不区分大小写。xxx
完整的大小写很难,但它可以(在大多数情况下)完成,正如Perl和Ruby所证明的那样。但是,在你应该理解的地方,它也是相当不直观的(阅读:令人惊讶)。你必须用括号中的字符类做一些特殊的事情,特别是对它们的否定,否则会导致胡说八道。
区域设置匹配
最后,要使事情真正复杂化,在现实世界中,你必须做的不仅仅是事例映射和归一化。在某些国家/地区,情况更为复杂。例如,在德语电话簿中,带有元音变音符的元音与相同的基本元音后跟字母 e 的计数完全相同。因此,在那里,类似的东西有望在不区分大小写的情况下进行匹配。müß
MUESS
要正确完成所有这些操作,您不仅需要绑定完整的大小写映射和规范化表、DUCET 本身、默认 Unicode 排序规则元素表,甚至 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";
}
如果你运行它,你会发现它确实有效:
在 ‹Ich müß Perl studieren 中位置 4 处找到文字 ‹MUESS› 的匹配项。› 作为 ‹müß›
参考书目
这些例子中的大多数都是从第4版的Programming Perl中获取的,并得到了其作者的许可。:)我在那里写了很多关于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一直很好心地为我维护。
进一步阅读
另请参阅: