LINUX.ORG.RU

Сравнение строк в Java с хитрым учетом локалей

 , , ,


0

3

Итак, хочется, что бы выполнялись 3-й и 4й ассерты, но ничего не могу придумать.

com.ibm.icu уже весь облазил, Collator работает не так, как кажется - если высталять аттрибут Strengh=Primary, то сравнение происходит без учета регистра (и это не отключается, там как бы охватывающее условие), а мне нужно с учетом регистра.

import java.lang.Math;
import java.lang.String;
import com.ibm.icu.text.Normalizer2;


public class HelloWorld {

 public static boolean equalsIgnoreCaseMy(CharSequence s, CharSequence t) {
  Normalizer2 normalizer = Normalizer2.getNFKCCasefoldInstance();
  return normalizer.normalize(s).equals(normalizer.normalize(t));
 }

 public static void main(String[] args) {
  String s1 = "Hello";
  String s2 = "hello";

  assert s1.equalsIgnoreCase(s2);


  String brook = "\uFB02u\u0308\u00DFchen"; // "flüßchen"
  String BROOK = "FL\u00DCSSCHEN"; // "FLÜSSCHEN"

  assert equalsIgnoreCaseMy(brook, BROOK);

  String e1 = "encyclopaedia";
  String E1 = "Encyclopaedia";
  String e2 = "encyclop\u00E6dia"; // "encyclopædia"

  assert equalsWHAT(e1, e2); // №3
  assert false == equalsWHAT(E1, e2); // №4

 }
}

Дело в том, что такой код на C# работает

  String e1 = "encyclopaedia";
  String E1 = "Encyclopaedia";
  String e2 = "encyclop\u00E6dia"; // "encyclopædia"

  Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
  Debug.Assert( string.Equals(e1, e2, StringComparison.CurrentCulture) );
  Debug.Assert( !string.Equals(E1, e2, StringComparison.CurrentCulture) );

Но меня интересует только Ява и указанное поведение. C# приведен как пример того, что такое поведение мне потребовалось не на пустом месте.

Спасибо

Deleted

Последнее исправление: maxcom (всего исправлений: 6)

По теме коддинга я сказать могу мало, а вот по строках для 3 и 4 ассертов: а Юникод что вот пишет на такой случай? Помоем так ожидать нельзя что-бы 2 буквы сравнивались с третей без дополнительных указаний на это. Там должно быть что-то типа специального кодепоинта который делает склейку?

FeyFre ★★★★
()
Ответ на: комментарий от FeyFre

Нагугливается подсказка что конкретно этот символ из Шведского языка может бы приравнен к ae. Стоит поменять локаль коллатору?

FeyFre ★★★★
()

http://stackoverflow.com/questions/8389922/where-can-i-find-a-specific-set-of...

Эти строки ровны только в определённых локалях (в датском например не равны) в других могут быть равны

{
            Locale uiLocale = Locale.forLanguageTag("da-DK");

            // Setting up collator object
            Collator collator = Collator.getInstance(uiLocale);
            collator.setStrength(Collator.SECONDARY);
            collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
            // strings for equality testing
            String test1 = "USA lover Grækenland støtte";
            String test2 = "USA lover graekenland støtte";
            boolean result = collator.equals(test1, test2);
            System.out.println("" + result);
        }
        {
            Locale uiLocale = Locale.forLanguageTag("en-US");

            // Setting up collator object
            Collator collator = Collator.getInstance(uiLocale);
            collator.setStrength(Collator.SECONDARY);
            collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
            // strings for equality testing
            String test1 = "USA lover Grækenland støtte";
            String test2 = "USA lover graekenland støtte";
            boolean result = collator.equals(test1, test2);
            System.out.println("" + result);
        }
false
true

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 4)

Вот вы все правильно говорите. Только наоборот - в датском эти буквы не равны. А в en-US - равны.

Коллатор это хорошо. Но он ищет только БЕЗ учета регистра, если его настроить таким образом, что 'æ' == 'ae', к сожалению. В посте я указал.

Т.е. я делаю коллатор с «da_DK», тогда E1 != e2, делаю коллатор с «en_US» - E1 == e2. Но проблема в том, что регистрозависимый случай не отрабатывает, т.е. не могу подобрать параметры, когда e1 == e2 && E1 != e2. Что в en_US, что в da_DK.

Deleted
()
Ответ на: комментарий от vtVitus

Да. Но...

case-sensitive не работает. И не могу понять, почему.

т.е.

            String test10 = "USA lover grækenland støtte";
            String test1  = "USA lover Grækenland støtte";
            String test2  = "USA lover graekenland støtte";

assert test10 == test2;
assert test1 != test2;

- такое хочу.

Всегда либо test10 == test2 && test1 == test2, либо test10 != test2 && test1 != test2, но найти настройки каллатора, что бы было test10 == test2 && test1 != test2 - не получается

Кстати, SECONDARY мне не хватает, приходится ставить PRIMARY. У тебя реально работает с SECONDARY или это чей-то глюк (у меня рабочей машины нет под рукой сейчас)? А декомпозиция совсем на это не влияет. CASE_LEVEL - это так же не подходит, оно о другом.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 6)
Ответ на: комментарий от Deleted

Кстати, SECONDARY мне не хватает, приходится ставить PRIMARY. У тебя реально работает с SECONDARY или это чей-то глюк (у меня рабочей машины нет под рукой сейчас)?

        Collator collator = Collator.getInstance(Locale.US);
        collator.setStrength(Collator.SECONDARY);
        collator.setDecomposition(Collator.NO_DECOMPOSITION);

        String s1 = "encyclopaedia";
        String s2 = "Encyclop\u00E6dia";
        System.out.println(collator.equals(s1, s2));

выводит true

Legioner ★★★★★
()
Ответ на: комментарий от Deleted

не могу понять, почему

Это как раз понятно — такая реализация в JDK. Как сделать — непонятно. В ICU такая же логика. Только пытаться искать другие библиотеки, может быть попробовать какую-нибудь реализацию на C подключить через JNI.

Legioner ★★★★★
()
Ответ на: комментарий от Deleted

SECONDARY хватает. за размер букв отвечает более сильное TERTIARY, но тогда перестаёт работать æ <-> ae, что логично с точки зрения применения каллаторов т.е. для сортировки. Для твоего случая навскидку даже ничего не приходит в голову.

vtVitus ★★★★★
()
Ответ на: комментарий от Legioner

Ну раз ниточки ведут в dotnet, надо код из mono попробовать заюзать :) Доля шутки в этом есть...

Deleted
()

Попробуй либу на C# написать раз там все работает и заюзать http://jni4net.com/ , или сделать AOT компиляцию либы на Mono и заюзать обычный JNI.

anonymous
()
Ответ на: комментарий от proud_anon

Вроде, топик исчерпывающий, и дискуссия была плодотворная. Странно видеть твой комментарий. Но всеравно спасибо за ссылку.

Deleted
()

Решили не париться пока над 100% совместимостью с dotnet-поведением. Если в дальнейшем понадобится, скорее всего, будет искаться библиотека помимо ICU; возможно, как упоминалось, как-то связаться с mono.

Deleted
()
Ответ на: комментарий от proud_anon

Кстати, для ясности. 'æ' в английском языке это так называемая лигатура, непосредственно соответствующая паре 'ae' на письме. А вот как раз в датском - это отдельная буква.

Подтверждение вот http://www.fileformat.info/info/unicode/char/00e6/index.htm Про лигатуры - вики.

Еще английская лигатура, например, 'fi' == 'f‌i'. В немецком - лигатруй является 'ß'.

Мне тут объяснили, что, например, текст может быть отверстан в PDF с использованием лигатур, а поиск должен работать корректно. Поэтому, вот.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.