Шаблон регулярных выражений с Unicode не выполняет сворачивание регистра

В C# кажется, что Grüsse а также Grüße считаются равными в большинстве случаев, как это объясняется на этой хорошей веб-странице. Я пытаюсь найти подобное поведение в Java - очевидно, не в java.lang.String,

Я думал, что мне повезло с java.regex.Pattern в комбинации с Pattern.UNICODE_CASE, Javadoc говорит:

UNICODE_CASE включает сведение дел с учетом Unicode. Если указан этот флаг, то сопоставление без учета регистра, если оно разрешено флагом CASE_INSENSITIVE, выполняется способом, совместимым со стандартом Unicode.

Еще следующий код:

Pattern p = Pattern.compile(Pattern.quote("Grüsse"), 
                     Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
System.out.println(p.matcher("Grüße").matches());

доходность false, Зачем? И есть ли альтернативный способ воспроизведения поведения сворачивания C#?

---- редактировать ----

Как отметил @VGR, String.toUpperCase преобразует ß в ss, который может быть, а может и не складываться (возможно, я путаю понятия здесь). Однако другие символы в немецком языке не "свернуты", например ü не становится UE, Итак, чтобы сделать мой первоначальный пример более полным, есть ли способ сделать Grüße а также Gruesse сравнить равные в Java?

Я думал java.text.Normalizer класс может быть использован для этого, но он преобразует ü в u? скорее, чем ue, Он также не имеет возможности предоставить Locale, что смущает меня еще больше.

3 ответа

Решение

Для справки приведены следующие факты:

  • Character.toUpperCase() не может выполнить сворачивание регистра, поскольку один персонаж должен отображаться на один символ.

  • String.toUpperCase() сделаю складывание чехла.

  • String.equalsIgnoreCase() использования Character.toUpperCase()внутренне, так что не делать складывания.

Вывод (как указывал @VGR): если вам нужно сопоставление без учета регистра и свертывание регистра, вам нужно сделать:

foo.toUpperCase().equals(bar.toUpperCase())

и не:

foo.equalsIgnoreCase(bar)

Для ü а также ue равенство, мне удалось сделать это с RuleBasedCollator и мои собственные правила (можно было бы ожидать Locale.German было то встроенное но увы). Это выглядело действительно глупо / чрезмерно сконструировано, и так как мне нужно было только равенство, а не сортировка / сортировка, в конце концов я остановился на простом наборе String.replace до сравнения. Это отстой, но это работает и прозрачно / читабельно.

Используйте регулярные выражения ICU4J, а не JDK: http://userguide.icu-project.org/strings/regexp

С принятым в настоящее время ответом:

      foo.toUpperCase().equals(bar.toUpperCase())

Следующие входные данные не сравниваются как равные, хотя должны: Grüsseа также ; или же Grüße а также GRÜẞE.

Это почему? Давайте посмотрим на строки в верхнем регистре:

      "Grüsse".toUpperCase(Locale.ROOT)  -> "GRÜSSE"
"Grüße".toUpperCase(Locale.ROOT)   -> "GRÜSSE"
"GRÜẞE".toUpperCase(Locale.ROOT)   -> "GRÜẞE"

Как видите, заглавная буква «резкая S» () остается неизменной. Чтобы справиться с этим правильно, сделайте следующее:

      foo.toLowerCase(Locale.ROOT).toUpperCase(Locale.ROOT).equals(
    bar.toLowerCase(Locale.ROOT).toUpperCase(Locale.ROOT))

Обратите внимание, что порядок важен. Если вы сначала прописываете верхний регистр, а затем строчный, он превратится в ß (только строчная буква S).

Другие вопросы по тегам