Сопоставление Java игнорирует пространство

Недавно я понял, что Java Collation, похоже, игнорирует пробелы.

У меня есть список следующих терминов:

Amman Jost 
Ammann Heinrich 
Ammanner Josef 
Bär Walter 
Bare Werner 
Barr Burt 
Barraud Maurice

Приведенный выше порядок отражает желаемый порядок для Германии, т.е. занимает пространство в счет. Однако Java Collation с использованием

Collator collator = Collator.getInstance(Locale.GERMANY);
Collections.sort(values, collator);

дает мне следующий порядок:

Amman Jost
Ammanner Josef
Ammann Heinrich
Bare Werner
Barraud Maurice
Barr Burt
Bär Walter

Результат выше не является тем, что я ожидал, поскольку пространства не учитываются (выглядит так, как описано здесь: Википедия Алфавитный порядок).

Означает ли это, что Java Collation не используется для такого использования или я что-то не так здесь делаю? Есть ли способ сделать пространство Java Collation осведомленным?

Буду рад за любые комментарии или рекомендации.

Ответ 1

Вы можете настроить сортировку. Попробуйте найти исходный код, чтобы узнать, как создается Collator для немецкого языка, как описано в этом ответе.

Затем адаптируйте его к вашим потребностям. tutorial дает начальную точку. Но не нужно делать всю работу, кто-то еще это сделал: см. Это сообщение в блоге, посвященное той же проблеме для чешского языка.

Суть решения, связанного выше:

String rules = ((RuleBasedCollator) Collator.getInstance(Locale.GERMANY)).getRules();
RuleBasedCollator correctedCollator 
    = new RuleBasedCollator(rules.replaceAll("<'\u005f'", "<' '<'\u005f'"));

Это добавляет правило для символа пробела перед правилом для подчеркивания.

Я признаюсь, что не проверял это лично.

Ответ 2

Если вы не можете изменить локаль по некоторым причинам, я бы предложил вам написать все самостоятельно. Вот некоторые идеи, хотя этот код не является полным и не работает:

  • Вместо того, чтобы иметь список строк, создайте свои собственные объекты, выполнив сопоставимые значения:

    public class myString implements Comparable<myString> {
        private String name;
    
        public myString(String name) {
           this.name = name;
        }
    }
    
  • Затем вам нужно будет реализовать (см. пример здесь)

    public int compareTo(myString compareMyString) {
        ...
    }
    
  • Теперь идет сложная часть:

    • Чтобы сравнить ваши строки, вам нужно разбить их (это приведет к массиву строк). Например:

      // Original String
      "Barr Burt"
      
      // Splitted String
      [0]: "Barr"
      [1]: "Burt"
      
    • Вам нужно будет сравнивать слова один за другим. Создайте функцию, выполняющую что-то вроде этого (это псевдокод: "this.words [i]" вызывает i-е слово "this.name" )

      public int compareWords(myString compareMyString, int i)
      {
          if (this.words[i] < compareMyString.words[i])
              return -1; // "this" should come before "compareMyString"
      
          if (this.words[i] > compareMyString.words[i])
              return 1; // "this" should come after "compareMyString"
      
          if (this.words[i] == compareMyString.words[i])
              return compareWords(i+1);
      }
      
    • И затем compareTo:

      public int compareTo(myString compareMyString) {
          return compareWords(compareMyString, 0);
      }