Обработка сортировки в приложениях

Некоторые приложения, такие как Microsoft Active Directory, Microsoft Exchange и Microsoft Access, поддерживают сортируемую базу данных языковых и языковых строк, индексируемых по имени (строка UTF-16), и связанные с ними весовые коэффициенты сортировки.

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

Функции сортировки

В приложениях можно использовать различные функции сортировки:

Обычно функции сортировки оценивают строки по символам. Однако во многих языках есть многосимвенные элементы, такие как двухсимвенная пара "CH" в традиционном испанском языке. CompareString и CompareStringEx используют предоставленный приложением идентификатор или имя языкового стандарта для идентификации элементов из нескольких символов. В отличие от этого, lstrcmp и lstrcmpi используют языковой стандарт пользователя.

Другим примером является вьетнамский, который содержит много двухзначных элементов, таких как допустимые прописные буквы, заголовок и строчные формы "GI", которые являются "GI", "Gi" и "gi" соответственно. Любая из этих форм рассматривается как единый элемент сортировки и, если регистр игнорируется, сравнивается как равное. Однако поскольку "gI" не является допустимым как один элемент, CompareString, CompareStringEx, lstrcmp и lstrcmpi рассматривают "gI" как два отдельных элемента.

Функции CompareString, CompareStringEx, lstrcmp, lstrcmpi, LCMapString, LCMapStringEx, FindNLSString и FindNLSStringEx по умолчанию используют метод сортировки слов. Для этого типа все знаки препинания и другие символы, не являющиеся цифрами, за исключением дефиса и апострофа, предшествуют любому буквенно-цифровому символу. Дефис и апостроф обрабатываются иначе, чем другие неальфаковые цифровые символы, чтобы такие слова, как "coop" и "co-op" оставались вместе в отсортированных списках.

Вместо сортировки по словам приложение может запросить метод "сортировки строк" из функций сортировки, указав флаг SORT_STRINGSORT. Строка сортировки обрабатывает дефис и апостроф так же, как и любой другой неальфаковый цифровой символ. Их позиции в последовательности сортировки находятся перед буквенно-цифровыми символами.

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

Сортировка Word Сортировка строк
Заготовки счета
Счета Заготовки
счета Счета
он не может Не
Наклоняю он не может
Не Наклоняю
Con совместное сотрудничество
Курятник Con
совместное сотрудничество Курятник

 

Лингвистическая сортировка строк

Функции CompareString и CompareStringEx проверяют лингвистическое равенство. Приложения должны использовать эти функции с правильным языковым стандартом для лингвистической сортировки строк.

Примечание

Для совместимости с Юникодом приложение должно предпочесть CompareStringEx или версию Юникода CompareString. Еще одна причина, по которой вы предпочитаете CompareStringEx , заключается в том, что корпорация Майкрософт переходит на использование имен языковых стандартов вместо идентификаторов языкового стандарта для новых языковых стандартов в целях взаимодействия. Любое приложение, работающее только в Windows Vista и более поздних версиях, должно использовать CompareStringEx.

 

Другим способом проверки на лингвистическое равенство является использование lstrcmp или lstrcmpi, которые всегда используют сортировку слов. Функция lstrcmpi вызывает CompareString с флагом NORM_IGNORECASE, а lstrcmp вызывает его без этого флага. Общие сведения об использовании функций-оболочек см. в разделе Строки.

Функции извлекают лингвистические результаты для всех языковых стандартов. Ожидания пользователей для разных языковых стандартов могут значительно отличаться в поведении сортировки, как показано в следующих примерах.

  • Многие языковые параметры приравнивают лигатуру ae (æ) к буквам ae. Однако исландийский (Исландия) считает его отдельной буквой и помещает его после Z в последовательности сортировки.
  • Кольцо A (Å) обычно сортируется с просто диакритической разницей от A. Однако шведский (Швеция) помещает кольцо после Z в последовательности сортировки.

Функции пытаются строго проверить, что кодовые точки, определенные в стандарте Юникода, канонически равны строке эквивалентных кодовых точек. Например, кодовая точка, представляющая строчную букву "u" с диерезами (ü), канонически равна нижнему регистру "u" в сочетании с диерезом (esis). Однако обратите внимание, что каноническая эквивалентность не всегда возможна.

Так как почти все данные, введенные с помощью клавиатуры Windows и редакторов методов ввода (МЕ), соответствуют формату нормализации C, определенной в стандарте Юникода, преобразование входящих данных с других платформ с помощью функций нормализации Юникода NLS обеспечивает наиболее согласованные результаты, особенно для языковых стандартов, использующих тибетский или хангыльский скрипт для современных хангыль. Дополнительные сведения о поддержке нормализации Юникода в Windows Vista и более поздних версиях см. в статье Использование нормализации Юникода для представления строк.

Если сравнение строк соответствует языковым предпочтениям пользователя, например при сортировке элементов для упорядоченного элемента управления ListView, приложение может выполнить одно из следующих действий:

  • Вызовите lstrcmp или lstrcmpi с языковым стандартом пользователя.
  • Вызовите CompareString или CompareStringEx, чтобы определить языковой стандарт для сравнения, передать дополнительные флаги, внедрить символы NULL или передать явную длину для сопоставления частей строки.

Если результаты сравнения должны быть согласованными независимо от языкового стандарта, например при сравнении полученных данных с предопределенным списком или внутренним значением, приложение должно использовать CompareString или CompareStringEx с параметром Locale , для которого задано значение LOCALE_INVARIANT. Для CompareString любой из следующих вызовов будет совпадать, даже если mystr имеет значение INLAP. В этом случае вызов lstrcmpi с учетом языкового стандарта завершится ошибкой, если текущим языковым стандартом является вьетнамский.

В Windows XP.

int iReturn = CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);

В более ранних операционных системах:

DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
int iReturn = CompareString(lcid, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);

Сортировка строк по порядковой сортировке

Для порядковой (нелингвистической) сортировки приложения всегда должны использовать функцию CompareStringOrdinal .

Примечание

Эта функция доступна только для Windows Vista и более поздних версий.

 

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

Все приведенные ниже инструкции применяются к CompareStringOrdinal в двоичных сравнениях, но не к CompareString, CompareStringEx, lstrcmp или lstrcmpi.

  • Канонически эквивалентные последовательности в Юникоде, такие как LATIN SMALL LETTER A WITH RING ABOVE (U+00e5) и LATIN SMALL LETTER A + COMBINING RING ABOVE (U+0061 U+030a), не равны, даже если они кажутся идентичными ("å").
  • Канонически похожие строки в Юникоде, такие как LATIN LETTER SMALL CAPITAL Y (U+028f) и LATIN CAPITAL LETTER Y (U+0059), которые выглядят очень похожими ("ʏ" и "Y") и различаются только некоторыми специальными весовыми коэффициентами в лингвистических таблицах, считаются совершенно непохожими символами. Даже если приложение устанавливает для bIgnoreCase значение TRUE, эти строки будут сравниваться как разные.
  • Кодовые точки, которые определены, но не имеют веса лингвистической сортировки, например ZERO WIDTH JOINER (U+200d), обрабатываются как имеющие весовые коэффициенты кодовых точек.
  • Кодовые точки, определенные в более поздних версиях Юникода, но не имеющие веса в текущих лингвистических таблицах, обрабатываются как имеющие весовые коэффициенты кодовых точек.
  • Кодовые точки, которые не определены в Юникоде, считаются имеющими весовые коэффициенты кодовых точек.
  • Когда приложение присваивает bIgnoreCase значение TRUE, функция сопоставляет регистр с использованием таблицы верхнего предела операционной системы, а не сведений в таблицах лингвистической сортировки. Таким образом, сопоставление не зависит от языкового стандарта.

Дополнительные сведения о канонически эквивалентных последовательностях в Юникоде и канонически похожих строках в Юникоде см. в разделе Использование нормализации Юникода для представления строк.

Сортировка кодовых точек

Некоторые кодовые точки Юникода не имеют веса, например ZERO WIDTH NON JOINER, U+200c. Функции сортировки намеренно оценивают невесовые кодовые точки как эквивалентные, так как они не имеют веса при сортировке. В Windows Vista и более поздних версиях приложение может сортировать эти кодовые точки, вызывая функции сравнения строк NLS, в частности CompareStringOrdinal, для вычисления всех кодовых точек в литеральном двоичном смысле, например при проверке пароля. В операционных системах, предшествующих Windows Vista, приложение должно использовать функцию среды выполнения C strcmp или wcscmp.

Функции сортировки игнорируют диакритические знаки, такие как NON SPACING BREVE, U+0306, когда приложение задает флаг hlink_NONSPACE. Аналогичным образом, эти функции игнорируют символы, например EQUALS SIGN, U+003d , когда указан флаг hlink_SYMBOLS. В Windows Vista и более поздних версиях приложение вызывает CompareStringOrdinal для оценки диакритических и символьных кодовых точек в литеральном двоичном смысле. В операционных системах, предшествующих Windows Vista, приложение должно использовать strcmp или wcscmp.

Некоторые кодовые точки, такие как 0xFFFF и 0x058b, в настоящее время не назначаются в Юникоде. Эти кодовые точки не получают вес при сортировке и никогда не должны передаваться в функции сортировки. Приложение должно использовать IsNLSDefinedString для обнаружения кодовых точек, отличных от Юникода, в потоке данных.

Примечание

Результаты IsNLSDefinedString могут отличаться в зависимости от передаваемой версии Юникода, если символ добавляется в Юникод в более поздней версии и впоследствии добавляется в таблицы сортировки Windows. Дополнительные сведения см. в разделе Использование управления версиями сортировки.

 

Сортировка цифр как чисел

В Windows 7 и более поздних версиях приложение может вызывать CompareString, CompareStringEx, LCMapString или LCMapStringEx с помощью флага SORT_DIGITSASNUMBERS. Этот флаг поддерживает сортировку, которая обрабатывает цифры как числа, например сортировку "2" перед "10".

Обратите внимание, что использование этого флага не подходит для шестнадцатеричных цифр, как показано ниже.

01AF
1BCD
002A
12FA
AB1C
AB02
AB12

В этом случае "числа" сортируются по порядку, но пользователь воспринимает плохо отсортированный шестнадцатеричный список.

Сопоставление строк

Приложение использует функцию LCMapString или LCMapStringEx для сопоставления строк, если LCMAP_SORTKEY не указан. Сопоставленная строка завершается со значением NULL, если исходная строка завершается null.

При преобразовании в верхнем и нижнем регистре функция не гарантирует, что один символ будет сопоставляться с одним символом. Например, флаги LCMAP_LOWERCASE и LCMAP_UPPERCASE могут сопоставлять немецкий шарп S ("ß") с самим собой. Кроме того, флаг LCMAP_UPPERCASE может сопоставлять "ß" с "SS", а флаг LCMAP_LOWERCASE может сопоставлять "SS" с "ß". Поведение зависит от версии NLS.

При преобразовании в верхнем и нижнем регистре функция не учитывает контекст. Например, в то время как флаг LCMAP_UPPERCASE правильно сопоставляет и греческую строчную сигму ("σ") и окончательную сигму греческого нижнего регистра ("σ") с греческой сигмой в верхнем регистре ("Σ"), флаг LCMAP_LOWERCASE всегда сопоставляет "Σ" с "σ", а не с "σ".

По умолчанию функция сопоставляет нижний регистр "i" с верхним регистром "I", даже если параметр Locale указывает турецкий или азербайджанский. Чтобы переопределить это поведение для турецкого или азербайджанского языка, приложение должно указать LCMAP_LINGUISTIC_CASING. Если этот флаг указан с соответствующим языковым стандартом, "ı" (нижний регистр без точек I) — это строчная форма "I" (i без точек в верхнем регистре), а "i" (строчная точка I) — строчная форма "İ" (точечная буква I).

Если флаг LCMAP_HIRAGANA указан для сопоставления символов катаканы с символами хираганы, а LCMAP_FULLWIDTH не указан, LCMapString или LCMapStringEx сопоставляет с хираганой только символы полной ширины. В этом случае все полуширитые символы катаканы помещаются как в целевую строку без сопоставления с хираганой. Приложение должно указать LCMAP_FULLWIDTH для сопоставления символов катаканы половинной ширины с хираганой. Причина этого ограничения заключается в том, что все символы хираганы являются символами полной ширины.

Если приложению необходимо удалить символы из исходной строки, оно может вызвать функцию сопоставления с установленными флагами NORM_IGNORESYMBOLS и NORM_IGNORENONSPACE, а все остальные флаги удалены. Если приложение делает это с исходной строкой, которая не завершается null, функция может вернуть пустую строку, а не ошибку.

Создание ключей сортировки

Когда приложение указывает LCMAP_SORTKEY, LCMapString или LCMapStringEx создает ключ сортировки, двоичный массив байтовых значений. Ключ сортировки не является истинной строкой, и его значения представляют поведение сортировки исходной строки, но не являются значимыми отображаемыми значениями.

Примечание

Функция игнорирует арабский kashida во время создания ключа сортировки. Если приложение вызывает функцию для создания ключа сортировки для строки, содержащей арабский kashida, функция не создает значение ключа сортировки.

 

Ключ сортировки может содержать нечетное количество байтов. Флаг LCMAP_BYTEREV отменяет только четное число байтов. Последний байт (нечетный) в ключе сортировки не отменяется. Если завершающий 0x00 байт является нечетным, он остается последним байтом в ключе сортировки. Если завершающий 0x00 байт является байтом с четным положением, он обменивается позициями с байтом, предшествующим ему.

При создании ключа сортировки функция обрабатывает дефис и апостроф не так, как другие символы препинания, чтобы такие слова, как coop и co-op, оставались вместе в списке. Все символы препинания, отличные от дефиса и апострофа, сортируются перед буквенно-цифровыми символами. Приложение может изменить это поведение, установив флаг SORT_STRINGSORT, как описано в разделе Функции сортировки.

При использовании в memcmp ключ сортировки создает тот же порядок, что и при использовании исходной строки в CompareString или CompareStringEx. Вместо strcmp следует использовать функцию memcmp, так как ключ сортировки может содержать встроенные байты NULL.

Использование управления версиями сортировки

Таблица сортировки содержит два числа, определяющих ее версию: определенную версию и версию NLS. Оба числа являются значениями DWORD, состоящими из основного и дополнительного значения. Первый байт значения зарезервирован, следующие два байта представляют основную версию, а последний байт представляет дополнительную версию. В шестнадцатеричных терминах шаблоном является 0xRRMMMMmm, где R равно Зарезервировано, M — основной, а m — младший. Например, основная версия 3 с дополнительной версией 4 представлена в виде 0x304.

Определенная версия определяет набор кодовых точек и одинакова для всех языковых стандартов. Приращение основной версии указывает на изменения существующих кодовых точек. Дополнительная версия увеличивается, чтобы указать, что кодовые точки были добавлены, но ранее существующие кодовые точки не были изменены.

Версия NLS зависит от идентификатора языкового стандарта или имени языкового стандарта и отслеживает изменения весов кодовых точек для затронутого языкового стандарта. Основная версия увеличивается при изменении весовых коэффициентов для кодовых точек, которые уже были сортируемыми. Дополнительная версия увеличивается, когда новым кодовым точкам присваиваются весовые коэффициенты, но все остальные ранее сортируемые весовые коэффициенты кодовых точек остаются неизменными.

Примечание

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

 

Важно!

Основная версия была изменена в Windows 8. Данные, созданные в более ранних версиях Windows, необходимо переиндексировать.

 

Как определенная, так и NLS-версии применяются к сортируемым точкам кода, извлекаемым с помощью функции LCMapString или LCMapStringEx с флагом LCMAP_SORTKEY, а также используемым функциями CompareString, CompareStringEx, FindNLSString и FindNLSStringEx . Если одна или несколько кодовых точек в строке являются несортируемыми, функция IsNLSDefinedString возвращает значение FALSE при передаче этой строки в качестве параметра.

Приложение может вызвать GetNLSVersion или GetNLSVersionEx , чтобы получить как определенную версию, так и версию NLS для таблицы сортировки.

Индексирование базы данных

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

Правильное индексирование базы данных

  1. Для каждой функции сохраните версию NLS, ключи сортировки этой версии и указание возможности сортировки для каждой индексируемой строки.
  2. При приращении дополнительной версии переиндексировать ранее несортируемые строки. Строки, затронутые в этом обновлении, должны быть ограничены теми, для которых IsNLSDefinedString ранее возвращал false.
  3. При приращении основной версии переиндексировать все строки, так как обновленные весовые коэффициенты могут изменить поведение любой строки. Выпуски основных версий происходят очень редко.

Проблемы с индексированием базы данных могут возникать по следующим причинам:

  • Более поздняя операционная система может определить кодовые точки, которые не определены для более ранней операционной системы, тем самым изменив сортировку.
  • Кодовые точки могут иметь разные весовые коэффициенты сортировки в разных операционных системах из-за исправлений в поддержке языка.

Чтобы свести к минимуму необходимость переиндексации базы данных в таких случаях, приложение может использовать IsNLSDefinedString для различения определенных строк и неопределенных строк, чтобы приложение пользовалось отклонением строк с неопределенными кодовыми точками. Использование GetNLSVersion или GetNLSVersionEx позволяет приложению определить, влияет ли изменение NLS на языковой стандарт, используемый для конкретной таблицы индексов. Если изменение не влияет на языковой стандарт, приложению не нужно переиндексировать таблицу.

Примеры

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

Символ 1 Символ 2 Значение по умолчанию NORM_IGNOREWIDTH NORM_IGNOREKANA NORM_IGNOREWIDTH| НОРМИНЬОРЕКАНА
"あ"
U+3042 ХИРАГАНА БУКВА A
"ガ"
U+30A2 КАТАКАНА БУКВА A
Неравные Неравные Равно Равно
"オ"
U+FF75 HALFWIDTH КАТАКАНА БУКВА O
"オ"
БУКВА O U+30AA KATAKANA
Неравные Равно Неравные Равно
"B"
U+FF22 FULLWIDTH ЛАТИНСКАЯ ПРОПИСНАЯ БУКВА B
"B"
U+0042 ЛАТИНСКАЯ ПРОПИСНАЯ БУКВА B
Неравные Равно Неравные Равно

 

Использование поддержки национальных языков

Сортировка

Получение и настройка сведений о языковом стандарте

Использование нормализации Юникода для представления строк

Вопросы безопасности: международные функции

CompareString

CompareStringEx

CompareStringOrdinal

FindNLSString

FindNLSStringEx

LCMapString

LCMapStringEx