Обработка сортировки в приложениях
Некоторые приложения, такие как Microsoft Active Directory, Microsoft Exchange и Microsoft Access, поддерживают сортируемую базу данных строк локали и языка, индексируемых по имени (строка UTF-16) и связанных с ними весовых значений для сортировки.
Сортировка обычно интуитивно понятна для пользователей в их собственных языковых настройках. Однако это может быть неинтуитивным для разработчиков приложений. В этом разделе рассматриваются рекомендации по обработке сортировки в приложениях. Сортировка может быть лингвистической или порядковой (нелингвистической).
Функции сортировки
В приложениях можно использовать различные функции сортировки:
- Функции сравнения строк NLS. Примерами являются CompareString и CompareStringEx, CompareStringOrdinal, LCMapString, LCMapStringEx, FindNLSString, FindNLSStringExи FindStringOrdinal. См. Вопросы безопасности: международные возможности для обсуждения проблем безопасности, связанных с функциями сравнения строк.
- Функции-оболочки, которые внутренне вызывают функции сравнения строк. Наиболее распространенными функциями являются lstrcmp и lstrcmpi, которые вызывают CompareString.
Обычно функции сортировки оценивают строки по символам. Однако многие языки имеют многосимвольные элементы, такие как двухсимвольная пара "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. Строковый сорт обрабатывает дефис и апостроф так же, как и любой другой нефанумерный символ. Их позиции в последовательности сортировки находятся перед буквенно-цифровыми символами.
В следующей таблице сравниваются результаты сортировки слов с результатами сортировки строк.
Сортировка слов | Сортировка строк |
---|---|
полено | счет |
Счета | полено |
счет | Счета |
не может | не может |
жаргон | не может |
Не | жаргон |
обмануть | co-op |
кооператив | афера |
co-op | кооператив |
Сортировка строк лингвистически
Функции CompareString и CompareStringEx проверяют лингвистическое равенство. Приложения должны использовать эти функции с правильным языковым стандартом для сортировки строк по лингвистическим правилам.
Заметка
Для совместимости с Юникодом приложение должно предпочесть CompareStringEx или версию Юникода CompareString. Еще одна причина предпочитать CompareStringEx заключается в том, что корпорация Майкрософт переходит на использование имен локалей вместо идентификаторов локалей для новых локалей для обеспечения совместимости. Любое приложение, работающее только в Windows Vista и более поздних версиях, должно использовать CompareStringEx.
Другим способом тестирования на лингвистическое равенство является использование lstrcmp или lstrcmpi, которые всегда используют сортировку слов. Функция lstrcmpi вызывает CompareString с флагом NORM_IGNORECASE, а lstrcmp вызывает его без этого флага. Общие сведения об использовании функций-оболочки см. в строках.
Функции получают лингвистически соответствующие результаты для всех языковых стандартов. Ожидания пользователей в различных языковых стандартах могут существенно различаться при сортировке, как показано в следующих примерах.
- Многие языковые стандарты приравнивают лигатуру ae (æ) к буквам ae. Тем не менее, исландский язык считает её отдельной буквой и помещает после Z в алфавитном порядке.
- А с кружочком (Å) обычно имеет лишь диакритическое отличие от A. Однако, в шведском языке (Швеция) А с кружочком помещается после Z в порядке сортировки.
Функции пытаются тщательно проверить, что точки кода, определенные в стандарте Юникода, канонически равны строке эквивалентных точек кода. Например, кодовая точка, представляющая строчную букву u с диерезом (ü), канонически равна нижнему регистру u в сочетании с диереза (ü). Однако обратите внимание, что каноническая эквивалентность не всегда возможна.
Так как почти все данные, введенные с помощью клавиатур Windows и редакторов методов ввода (IMEs), соответствуют нормализации формы C, определенной в стандарте Юникода, преобразование входящих данных из других платформ с помощью функций нормализации Юникода NLS обеспечивает наиболее согласованные результаты, особенно для языковых стандартов, использующих тибетскую письменность или алфавит Хангыля для современных версий алфавита хангыля. Дополнительные сведения о поддержке нормализации Юникода в Windows Vista и более поздних версиях см. в разделе "Использование нормализации Юникода для представления строк".
Если сравнение строк следует предпочтениям языка пользователя, например при сортировке элементов для упорядоченного элемента управления ListView, приложение может выполнить одно из следующих действий:
- Вызовите lstrcmp или lstrcmpi с локализацией пользователя.
- Вызовите CompareString или CompareStringEx для определения языкового стандарта для сравнения, передачи дополнительных флагов, внедрения пустых символов или передачи явных длин для сопоставления частей строки.
Если результаты сравнения должны быть согласованы независимо от локали, например, при сравнении извлеченных данных с предопределенным списком или внутренним значением, приложение должно использовать 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, функция сопоставляет вариант с использованием таблицы верхнего слоя операционной системы вместо сведений в таблицах лингвистической сортировки. Таким образом, сопоставление не зависит от локали.
Дополнительные сведения о канонически эквивалентных последовательностях в Юникоде и канонически аналогичных строках в Юникоде см. в разделе Использование нормализации Юникода для представления строк.
Сортировка точек кода
Некоторые точки кода Юникода не имеют веса, например НУЛЕВОЙ ШИРИНЫ 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", даже если параметр языкового стандарта указывает турецкий или азербайджанский. Чтобы переопределить это поведение для турецкого или азербайджанского языков, приложение должно указать LCMAP_LINGUISTIC_CASING. Если этот флаг указан с соответствующим языковым стандартом, "ı" (строчная I без точки) является строчной формой "I" (прописная I без точки), а "i" (строчная I с точкой) является строчной формой "İ" (прописная I с точкой).
Если флаг LCMAP_HIRAGANA указан для сопоставления символов катаканы с символами hiragana и LCMAP_FULLWIDTH не указан, LCMapString или LCMapStringEx сопоставляет только символы полной ширины с hiragana. В этом случае символы катаканы половинной ширины размещаются в конечной строке без соответствия хирагане. Приложение должно указать LCMAP_FULLWIDTH для преобразования символов катаканы половинной ширины в хирагану. Причиной этого ограничения является то, что все символы hiragana являются полной шириной символов.
Если приложению необходимо удалить символы из исходной строки, оно может вызвать функцию сопоставления, установив флаги NORM_IGNORESYMBOLS и NORM_IGNORENONSPACE, а все остальные флаги сбросив. Если приложение делает это с исходной строкой, которая не завершается значением NULL, функция может возвращать пустую строку и не возвращать ошибку.
Создание ключей сортировки
Если приложение указывает LCMAP_SORTKEY, LCMapString или LCMapStringEx создает ключ сортировки, двоичный массив байтовых значений. Ключ сортировки не является истинной строкой, а его значения представляют поведение сортировки исходной строки, но не являются значимыми значениями отображения.
Заметка
Функция игнорирует арабскую кашиду во время создания ключа сортировки. Если приложение вызывает функцию для создания ключа сортировки для строки, содержащей арабскую кашиду, то функция не создает никакого значения ключа.
Ключ сортировки может содержать нечетное число байтов. Флаг LCMAP_BYTEREV переворачивает только четное число байтов. Последний байт (расположенный на нечетной позиции) в ключе сортировки не переворачивается. Если завершающий 0x00 байт является нечетным байтом, он остается последним байтом в ключе сортировки. Если завершающий 0x00 байт является четным байтом, он обменивается позициями с байтом, предшествующим ему.
При создании ключа сортировки функция обрабатывает дефис и апостроф иначе, чем другие символы препинания, чтобы такие слова, как "coop" и "co-op", оставались вместе в списке. Все символы препинания, за исключением дефиса и апострофа, сортируются до буквенно-цифровых символов. Приложение может изменить это поведение, задав флаг SORT_STRINGSORT, как описано в разделе Сортировка функций.
При использовании в memcmpключ сортировки создает тот же порядок, что и при использовании исходной строки в CompareString или CompareStringEx. Функцию memcmp следует использовать вместо strcmp, так как ключ сортировки может содержать встроенные байты 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 для таблицы сортировки.
Индексирование базы данных
По соображениям производительности приложение должно следовать этой процедуре при индексировании базы данных.
Для правильного индексирования базы данных
- Для каждой функции сохраните версию NLS, ключи сортировки этой версии и признаки сортировки для каждой индексируемой строки.
- При увеличении второстепенной версии повторно индексируйте ранее несортируемые строки. Строки, затронутые в этом обновлении, должны быть ограничены теми, для которых IsNLSDefinedString ранее возвращал FALSE.
- Когда главная версия увеличивается, все строки повторно индексируются, так как обновленные весовые значения могут изменить поведение любой строки. Выпуски основных версий очень редки.
Проблемы с индексированием баз данных могут возникнуть по следующим причинам:
- Более поздняя операционная система может определить кодовые точки, которые не определены для более ранней операционной системы, таким образом изменяя сортировку.
- Точки кода могут иметь разные весовые значения сортировки в разных операционных системах из-за исправлений в поддержке языка.
Чтобы свести к минимуму необходимость повторно индексировать базу данных в этих обстоятельствах, приложение может использовать IsNLSDefinedString для отличия определенных строк от неопределенных строк, чтобы приложение может отклонять строки с неопределенными точками кода. Использование GetNLSVersion или GetNLSVersionEx позволяет приложению определить, влияет ли изменение NLS на локаль, используемую для конкретной индексной таблицы. Если изменение не влияет на локаль, приложению не нужно переиндексировать таблицу.
Примеры
В следующей таблице показаны эффекты определенных флагов, используемых с функциями сортировки. В каждом случае выбор флагов определяет, считаются ли два разных символа равными для сортировки.
Персонаж 1 | Символ 2 | По умолчанию | NORM_IGNOREWIDTH | NORM_IGNOREKANA | NORM_IGNOREWIDTH| НОРМИНЬОРАКАНА |
---|---|---|---|---|---|
"あ" U+3042 HIRAGANA ПИСЬМО A |
"ガ" U+30A2 КАТАКАНА БУКВА А |
Неравноправный | Неравный | Равный | Равный |
"オ" U+FF75 HALFWIDTH KATAKANA LETTER O |
"オ" U+30AA буква катакана О |
Нера́венство | Равный | Неравный | Равный |
В U+FF22 ШИРОКОФОРМАТНАЯ ЛАТИНСКАЯ ПРОПИСНАЯ БУКВА B |
"B" ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА B U+0042 |
Неравный | Равный | Неравный | Равный |
Связанные разделы