Ответ 1
В случае складывания флагов
Ответ: нет, точка будет не соответствовать ss
нечувствительно к регистру, хотя причины немного эзотеричны.
Тем не менее, ваша головоломка часто поднималась некоторыми из тех, кто больше знал о таких вещах, потому что они тоже чувствуют, что это приводит к противоречиям.
В Юникоде существует две формы отображения случаев. Существует простое отображение случаев, в котором одна кодовая точка только когда-либо отображает только одну другую кодовую точку. Поэтому, если length(s) == 1
, то вам гарантируется, что length(fc(s)) == 1
также, где fc
является картой памяти Unicode. Но это также относится к отображениям 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
В полном корпусе, а не в простом корпусе, который использует Javas regex, вы можете получить такие вещи, как tschüß
и TSCHÜSS
, даже если они имеют неравную длину. Perl и Ruby используют полное отображение случаев при выполнении нечувствительных к регистру сравнений. Это приводит к странным парадоксам в отрицательных классах персонажей, если вы не слишком осторожны.
Но это означает, что нечувствительность к тегу: нечувствительность к регистру не выполняет транзитивную операцию. Другими словами, если .
соответствует ß
и при нечувствительном к регистру совпадении, ß
соответствует ss
, это не означает, что с помощью транзитивности .
не учитывается регистр ss
. Это просто так не работает, хотя более умные люди, чем я, глубоко задумались над этим.
Однако обе эти кодовые точки:
- U + 00DF ß LATIN SMALL LETTER SHARP S
- U + 1E9E ẞ LATIN CAPITAL LETTER SHARP S
безусловно, нечувствительны к регистру не только друг другу, но и ss
, ss
, ss
и ss
при полном отображении случаев. Они просто не делают этого при простом сопоставлении случаев.
Unicode делает некоторые гарантии об этом. Во-первых, если 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)
и аналогичным образом для оператора сопоставления шаблонов =~
(который работает традиционным способом, но не как метод Javas broken 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";
}
Если вы запустите это, вы обнаружите, что он действительно работает:
Найдено совпадение буквального в позиции 4 в как
Выбранная библиография
Большинство этих примеров были взяты из версии 4 th программирования Perl по любезному разрешению ее автора.:) Я пишу совсем немного о таких вопросах Юникода, но не общих для 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, который Брайан Фой был достаточно любезен, чтобы поддерживать меня.
Для дальнейшего чтения
См. также: