Шаблон регулярных выражений с 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).