# #go #unicode #case-insensitive
Вопрос:
В golang (go1.17 windows / amd64) приведенная ниже программа выдает следующий результат:
rune1 = U 0130 'İ'
rune2 = U 0131 'ı'
lower(rune1) = U 0069 'i'
upper(rune2) = U 0049 'I'
strings.EqualFold(İ, ı) = false
strings.EqualFold(i, I) = true
Я думал, что strings.EqualFold
это проверит строки на равенство при сворачивании регистра в Юникоде; однако приведенный выше пример, похоже, дает встречный пример. Очевидно, что обе руны можно сложить (вручную) в кодовые точки, которые равны при сгибании регистра.
Вопрос: правильно ли это golang strings.EqualFold(İ, ı)
false
? Я ожидал, что это даст true
результат. И если golang верен, почему это должно быть? Или это поведение соответствует некоторой спецификации Unicode.
Чего мне здесь не хватает.
Программа:
func TestRune2(t *testing.T) {
r1 := rune(0x0130) // U 0130 'İ'
r2 := rune(0x0131) // U 0131 'ı'
r1u := unicode.ToLower(r1)
r2u := unicode.ToUpper(r2)
t.Logf("nrune1 = %#Unrune2 = %#Unlower(rune1) = %#Unupper(rune2) = %#Unstrings.EqualFold(%s, %s) = %vnstrings.EqualFold(%s, %s) = %v",
r1, r2, r1u, r2u, string(r1), string(r2), strings.EqualFold(string(r1), string(r2)), string(r1u), string(r2u), strings.EqualFold(string(r1u), string(r2u)))
}
Ответ №1:
Да, это «правильное» поведение. Эти буквы не ведут себя нормально при сгибании регистра. Смотрите: http://www.unicode.org/Public/UCD/latest/ucd/CaseFolding.txt
U 0131 имеет полное сгибание регистра «F» и специальное «T»:
T: special case for uppercase I and dotted uppercase I
- For non-Turkic languages, this mapping is normally not used.
- For Turkic languages (tr, az), this mapping can be used instead
of the normal mapping for these characters.
Note that the Turkic mappings do not maintain canonical equivalence
without additional processing.
See the discussions of case mapping in the Unicode Standard for more information.
Я думаю, что нет способа заставить строки пакета использовать отображение tr или az.
Ответ №2:
Из строк.EqualFold source — unicode.ToLower
и unicode.ToUpper
не используются.
Вместо этого он использует unicode.SimpleFold, чтобы увидеть, является ли конкретная руна «складной» и, следовательно, потенциально сопоставимой:
// General case. SimpleFold(x) returns the next equivalent rune > x
// or wraps around to smaller values.
r := unicode.SimpleFold(sr)
for r != sr amp;amp; r < tr {
r = unicode.SimpleFold(r)
}
Руна İ
не складывается. Это строчная кодовая точка:
r := rune(0x0130) // U 0130 'İ'
lr := unicode.ToLower(r) // U 0069 'i'
fmt.Printf("foldable? %vn", r != unicode.SimpleFold(r)) // foldable? false
fmt.Printf("foldable? %vn", lr != unicode.SimpleFold(lr)) // foldable? true
Если руна не складывается (т. Е. SimpleFold
Возвращает себя), то эта руна может соответствовать только самой себе и никакой другой кодовой точке.