пятница, 12 ноября 2010 г.

Что делает строку осмысленной?

Это перевод What makes a string meaningful? Автор: Майкл Каплан.

Вчера я сказал, что CompareString предпочитает осмысленные данные и хотя (редкие) несоответствия всегда являются багами, но нам приходится приоритезировать баги, основываясь на критерии осмысленности входных данных.

Многие люди задались вопросом, как определяется здесь слово "осмысленные". Если ли тут строгое определение или что-то, полезное для разработчиков?

Я проигнорирую меж-алфавитные строки, которые, очевидно, имеют мало семантического смысла, и сфокусируюсь на строках с кодовыми точками, не определёнными в таблицах сравнений MS (а иногда - и Unicode!).

Некоторые разработчики могут подумать, что они смогут использовать CompareString для сравнения символов со строкой нулевой длины. Другие могут решить использовать LCMapString в поисках ключа сортировки "без веса". Но обе эти идеи имеют две одинаковые проблемы, которые не дают им работать на практике:
  1. Проверка по одному символу за раз отличается сложностью, а по более чем одному за раз - может пропустить отдельные символы без веса.
  2. Некоторые кодовые точки Unicode не имеют веса специально и при этом являются полностью допустимыми. Например, U+2060 WORD JOINER.
Так что же вы можете сделать? Вы можете использовать API функцию IsNLSDefinedString! Вы передаёте ей строку, а она говорит вам, имеет ли каждый символ в строке определённый результат (который, в нашем случае, и является тем, что вы ищете).

Это тесно связано с GetNLSVersion, которая также помогает с вопросом о стабильности в сортировке.

Обе API функции были добавлены в Windows Server 2003, и в Whidbey релиз .NET Framework (прим.пер.: Whidbey - это codename Visual Studio 2005: насколько я понимаю это .NET 2.0), включая метод, аналогичный IsNLSDefinedString (CompareInfo.IsSortable - вы увидите их, начиная с Beta 2).

GetNLSVersion используется основными базами данных, вроде Active Directory, чтобы определить, когда им нужно пере-индексировать свои данные. В общем-то, глядя на запись TNLSVersionInfo, можно увидеть, что поле dwDefinedVersion будет увеличиваться каждый раз при значительном изменении сортировки, а поле dwNLSVersion будет увеличиваться при незначительных изменениях сортировки.

Теперь, глядя на IsNLSDefinedString: если у вас создана база данных и созданы индексы на базе ключах сортировки от LCMapString (или B-Trees построенные на базе CompareString):
  1. Если увеличивается основная версия (значительное изменение), вам нужно переиндексировать БД немедленно.
  2. Если увеличивается вторичная версия (незначительное изменение), то вам нужно переиндексировать все записи, для которых IsNLSDefinedString раньше возвращала False (в случае, если она сейчас возвращает True или разные результаты, от того, что часть строки теперь стала определена).
Очевидно, что значительные изменения дорогостоящи и они делаются редко - даже новая версия Windows далеко не всегда требует полной переиндексации.

Почему так? Ну, обычно новая версия просто означает, что была добавлена куча новых символов, и поэтому нет необходимости переиндексировать строки, что уже проиндексированы. Это и есть незначительное обновление. Они встречаются намного чаще. При таком изменении вы можете доверять уже проиндексированным существующим значениям, и вам нужно только переиндексировать строки, которые раньше содержали несортируемые элементы.

Если вы будете всегда следовать принципам (1) и (2) выше и всегда хранить информацию о несортируемых строках, вы сможете использовать эти API функции для максимизации эффекта от поддержки сравнений осмысленных строк в Windows.

This post brought to you by "" (U+10e5, a.k.a. GEORGIAN LETTER KHAR)

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.