Следующий код C# возвращает false при использовании .NET 6, который использует библиотеку ICU для сравнения строк:
Thread.CurrentThread.CurrentCulture = new CultureInfo("de-de");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-de");
"ß".Equals("SS", StringComparison.CurrentCultureIgnoreCase); // false with ICU
Насколько я понимаю, это должно быть правдой на основе правил складывания регистра Юникода (а также, что более важно, стандартных немецких орфографических правил):
00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S
(CaseFolding.txt)
При использовании устаревшей реализации Microsoft NLS приведенный выше код возвращает true.
Так почему же библиотека ICU, используемая .NET 6, отличается от стандарта Unicode или мое понимание стандарта здесь неверно?
Оригинальный вопрос C#, который привел к этому.
@Fildor «Насколько я понимаю, это должно быть правдой, исходя из правил свертывания регистра в Юникоде», но я могу сделать это немного яснее, чтобы избежать недоразумений.
Непонятно, какой ответ вы хотите получить от такого вопроса «почему». Это лучше подходит для отчета об ошибке для отделения интенсивной терапии, чем для вопроса о переполнении стека.
.NET 6 не использует специальную реализацию ICU. Само отделение интенсивной терапии ведет себя по-другому. В документах указано, что ß
должно соответствовать ss
в поиске и регулярном выражении, но ничего не говорится о равенстве.
@Sweeper Предполагается, что это ошибка, а не неправильное понимание спецификации с моей стороны. Ответ вполне может быть таким: «Параграф X последней спецификации говорит, что это приемлемое поведение».
Баг это или нет, особого значения не имеет. Многие заявки решаются словами «не проблема», «преднамеренно» и тому подобное. Я хочу сказать, что вы, скорее всего, получите лучшие ответы, отправив отчет об ошибке, а не публикуя вопрос о переполнении стека.
@Sweeper, это правильный вопрос, затрагивающий довольно много людей. И согласно документации по поиску строк ICU, "Heisse".Contains("ß")
должно работать. Немецкие правила были созданы не вчера, и немецкий рынок не является второстепенным. Когда Microsoft раньше говорила о «локализованности», она имела в виду только французский, немецкий и испанский языки. Это может быть ошибка или может потребоваться другое кодирование.
Фактически, в документах явно упоминается pattern “ß” will find occurrences of “ss” or “ß”.
в качестве примера.
Итак, я понимаю это как «это ошибка или я что-то упускаю»… Я действительно думаю, что и Свипер, и Панайотис правы. С одной стороны, было бы полезно получить ответ на соответствующим образом сформулированный отчет об ошибке, с другой стороны, было бы хорошо, если бы у кого-нибудь (в SO) уже был ответ и практическое решение - ошибка или нет.
Например, если я ищу ß
на этой странице, он также соответствует всем экземплярам SS
(в Edge).
^^ Как ни странно, этого нет в Firefox на немецкой Windows 10.
Это... еще страннее
Совпадения на Chrome, Brave,...
Инструмент тестирования отделения интенсивной терапии также сравнивает их, как и ожидалось. Такое ощущение, что библиотека ICU работает правильно, но что-то не так/отсутствует/непонятно при ее использовании в рамках.
@Ralf Это отличный инструмент, добавил его в закладки для будущего использования. Итак, теперь, когда я понял проблему, кажется, что отчет об ошибках для Microsoft готов. Посмотрим, что они скажут.
Я создал проблему с репозиторием dotnet теперь, когда мы, вероятно, изолировали проблему. Посмотрим, что из этого получится.
Юникод — это сложно.
Оказывается, такое поведение намеренное. См. этот выпуск Github по этому вопросу, где Тарекх резюмирует проблему:
При сортировке ICU используется так называемая сила сортировки. Сила может быть первичной, вторичной, третичной или четвертичной. Мы пытаясь сопоставить как можно больше вариантов сравнения .NET с одним из эти силы. которые работают нормально, за исключением таких особых случаев. К сожалению, ICU make ß равен ss только при наличии мощности ICU. является первичным. Мы не можем переключиться на эту силу по умолчанию в .NET. потому что это сломает много других вещей.
Уровень сортировки по умолчанию, используемый .NET, является третичным и вторичным для сравнений без учета регистра (насколько я могу судить по коду).
Обходной путь заключается в использовании StringComparer.Create(CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase)
- CompareOptions.IgnoreNonSpace
заставляет первичную силу сопоставления, и в этом случае ß
и ss
будут сравниваться равными.
Вероятно, этот переход приведет к некоторым непредвиденным побочным эффектам, но, по крайней мере, немецкоязычные будут счастливы.
Проголосовал за, сохранил и добавил в закладки. Самые ценные вопросы и ответы. Если бы можно было +2.
Как показывает этот ответ, сравнение основано на весах сопоставления, а не на строках с регистром. Различия по случаям в УЦА происходят на третичном уровне. Разница между ß
и ss
возникает не при третичной прочности, а скорее при вторичной прочности, согласно соответствующим стандартам DIN. Таким образом, нечувствительность к регистру, которая увеличивает силу сортировки с третичного на вторичный, не повлияет на разницу между весами сортировки ß
и ss
.
Это заявление. В чем здесь вопрос?