Нечувствительность к регистру и совместимость с Unicode

После того, как я услышал о ком-то на моей работе, используя String.toLowerCase() для хранения кодов, нечувствительных к регистру, в базе данных для поиска, у меня был epic fail момент, размышляющий о том, как он может пойти не так:

  • Тест в Турции (в частности, изменение локалей на рабочем компьютере)
  • Обновление версии Unicode - Я имею в виду, кто знает об этом? Если я обновляюсь до Java 7, мне нужно переиндексировать мои данные, если я не чувствителен к регистру?

Какие технологии затронуты версиями Unicode?

Нужно ли беспокоиться о том, что Oracle или SQL Server (или другие вендоры) меняют свои версии Unicode и приводят к тому, что одна из моих локаций не приводит к тому же преобразованию более низкого или верхнего символа?

Как мне это сделать? Я искушаюсь "простотой" обеспечения того, чтобы я использовал преобразование базы данных, но при обновлении это будет такая же проблема.

Ответ 1

Вы не хотите хранить строчную версию строки "для поиска"!

Это совсем не тот подход. Вы делаете несправедливые и неверные предположения о том, как работает Unicode корпус.

Вот почему Unicode определяет отдельную вещь, называемую caseofold для строки, отличную от трех разных случаев (строчные, строчные и прописные).

Вот десять разных примеров , где вы сделаете неправильную вещь, если вы используете строчный регистр вместо casefold:

ORIGINAL        CASEFOLD        LOWERCASE   TITLECASE  UPPERCASE
========================================================================
efficient         efficient       efficient       Efficient         EFFICIENT       
flour            flour           flour           Flour           FLOUR           
poſt            post            poſt           Poſt            POST            
poſt             post            poſt             Poſt            POST            
ſtop             stop            ſtop            Stop            STOP            
tschüß          tschüss         tschüß         Tschüß         TSCHÜSS         
weiß            weiss           weiß           Weiß            WEISS           
WEIẞ            weiss           weiß            Weiß           WEIẞ            
στιγμας         στιγμασ         στιγμας         Στιγμας         ΣΤΙΓΜΑΣ 
ᾲ στο διάολο    ὰι στο διάολο   ᾲ στο διάολο    Ὰͅ Στο Διάολο   ᾺΙ ΣΤΟ ΔΙΆΟΛΟ        

И да, я знаю, что множественное число стигмы - это стигматы, а не стигмы; Я пытаюсь показать окончательный вопрос сигмы. Оба ς и σ являются строчными версиями прописной сигмы Σ. Если вы храните "только строчную букву", тогда вы получите неправильную вещь.

Если вы используете класс Javas Pattern, вы должны указать как CASE_INSENSITIVE, так и UNICODE_CASE, и вы все равно не получите это правильно, потому что, хотя Java использует полное кэширование, он использует только простую фреймворку. Это проблема.

Что касается тюркских языков, да, это правда, что для тюркских есть особый случай. Например, в Стамбуле есть тюркский портфель просто ı̇stanbul вместо i̇stanbul, который вы должны получить. Поскольку я уверен, что они не будут выглядеть правильно, я расскажу вам об именованных символах для не-ASCII; в упрощенном выражении "\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}stanbul" имеет тюркский регистр из "\N{LATIN SMALL LETTER DOTLESS I}\N{COMBINING DOT ABOVE}stanbul", а не "i\N{COMBINING DOT ABOVE}stanbul", который вы обычно получаете.

Вот еще несколько строк таблицы, если вы пишете набор регрессионных тестов:

[ "Henry Ⅷ", "henry ⅷ", "henry ⅷ", "Henry Ⅷ", "HENRY Ⅷ",  ],
[ "I Work At Ⓚ",  "i work at ⓚ",  "i work at ⓚ", "I Work At Ⓚ", "I WORK AT Ⓚ", ],
[ "ʀᴀʀᴇ", "ʀᴀʀᴇ", "ʀᴀʀᴇ", "Ʀᴀʀᴇ", "ƦᴀƦᴇ",  ],
[ "Ԧԧ", "ԧԧ", "ԧԧ", "Ԧԧ", "ԦԦ",   ],
[ "𐐼𐐯𐑅𐐨𐑉𐐯𐐻", "𐐼𐐯𐑅𐐨𐑉𐐯𐐻", "𐐼𐐯𐑅𐐨𐑉𐐯𐐻", "𐐔𐐯𐑅𐐨𐑉𐐯𐐻", "𐐔𐐇𐐝𐐀𐐡𐐇𐐓",   ],
[ "Ὰͅ", "ὰι", "ᾲ", "Ὰͅ", "ᾺΙ",  ],

Если каждый столбец имеет начало, fold, lc, tc и uc, как и в предыдущей таблице выше. Еще раз обратите внимание на то, как последняя строка имеет caseofold, которая отличается от строчной.

Ответ 2

Укажите локаль для toLowerCase() вместо использования по умолчанию системы. Это защищает от изменений в локали системы.

Что касается возможных изменений Unicode в будущей версии Java, я не думаю, что стоит написать код для обработки этого. Документ, подтверждающий, что продукт поддерживает Java 6 и переходит к функции, которую действительно хотят ваши клиенты.

Ответ 3

Я думаю, что наиболее долгосрочным решением является

  • запишите текущую стандартную локаль и версию стека технологий (в моем случае версию Java) в конфигурацию
  • если он изменился (с момента последнего запуска или выполнения для локали - в зависимости от того, как он загружен указанным стеком технологий), затем заблокируйте хранилище и повторно проиндексируйте все затронутые наборы данных.

Очевидно, что это должно происходить на уровне основного интерфейса; если я делаю эти изменения в java, я надеюсь, что это мой единственный механизм интерфейса данных (например, другие специалисты не запрашивают хранилище таблиц)