Zpracování řazení v aplikacích
Některé aplikace, například Microsoft Active Directory, Microsoft Exchange a Microsoft Access, udržují seřazenou databázi národních prostředí a jazykových řetězců indexovaných podle názvu (řetězec UTF-16) a jejich přidružené váhy řazení.
řazení je obvykle intuitivní pro uživatele v jejich vlastním prostředí. Pro vývojáře aplikací ale může být neintuitivnější. Toto téma popisuje aspekty zpracování řazení v aplikacích. Řazení může být buď lingvistické, nebo řadové (nejazyčné).
Řazení funkcí
V aplikacích můžete použít různé funkce řazení:
- Funkce pro porovnání řetězců NLS. Příklady jsou CompareString a CompareStringEx, CompareStringOrdinal, LCMapString, LCMapStringEx, FindNLSString, FindNLSStringExa FindStringOrdinal. Viz aspekty zabezpečení: Mezinárodní funkce pro diskuzi o otázkách zabezpečení souvisejících s funkcemi porovnání řetězců.
- Funkce obalování, které interně volají funkce porovnání řetězců. Nejběžnějšími funkcemi jsou lstrcmp a lstrcmpi, které volají CompareString.
Funkce řazení obvykle vyhodnocují řetězce podle znaků. Mnoho jazyků však má víceznakových prvků, jako je dvojice dvou znaků "CH" v tradiční španělštině. CompareString a CompareStringEx použít identifikátor národního prostředí zadaný aplikací nebo název k identifikaci prvků s více znaky. Naproti tomu lstrcmpa lstrcmpi používají národní prostředí uživatele.
Dalším příkladem je vietnamština, která obsahuje mnoho dvouznakových prvků, jako jsou platná velká písmena, názvy s velkým počátečním písmenem a malá písmena "GI", což jsou "GI", "Gi" a "gi". Každý z těchto tvarů se považuje za jeden prvek řazení a pokud je ignorována velikost písmen, rovnají jako stejné. Protože však "gI" není platný jako jeden prvek, CompareString, CompareStringEx, lstrcmpa lstrcmpi považovat "gI" za dva samostatné prvky.
Funkce CompareString, CompareStringEx, lstrcmp, lstrcmpi, LCMapString, LCMapStringEx, FindNLSStringa FindNLSStringEx všechny používají ve výchozím nastavení techniku "řazení slov". U tohoto typu se všechny interpunkční znaky a další neosamocené znaky s výjimkou spojovníku a apostrofu dostanou před libovolný alfanumerický znak. Spojovník a apostrof se zachází jinak než s jinými nealfanumerickými znaky, aby se zajistilo, že slova jako "coop" a "co-op" zůstala pohromadě v seřazeném seznamu.
Místo řazení slov může aplikace požadovat metodu "řazení řetězců" z funkcí řazení zadáním příznaku SORT_STRINGSORT. Řazení řetězců zpracovává spojovník a apostrof stejně jako jakýkoli jiný nealfanumerický znak. Jejich pozice v pořadí řazení jsou před alfanumerickými znaky.
Následující tabulka porovnává výsledky řazení slov s výsledky řazení řetězců.
Řazení slov | Řazení řetězců |
---|---|
ubytování | Billův |
účty | ubytovat |
Billův | účty |
nemůže | nemůže |
sklon | nemůže |
nemůže | žargon |
proti | co-op |
kurník | proti |
co-op | kurník |
Řazení řetězců v lingvistice
Funkce CompareString a CompareStringEx testují jazykovou rovnost. Vaše aplikace by tyto funkce měly používat se správným národním prostředím pro lingvistické řazení řetězců.
Poznámka
Kvůli kompatibilitě s Kódováním Unicode by aplikace měla preferovat CompareStringEx nebo verzi Unicode CompareString. Dalším důvodem pro preferování CompareStringEx je, že Microsoft migruje na použití názvů národních prostředí místo identifikátorů národního prostředí pro nové národní prostředí z důvodů interoperability. Všechny aplikace, které běží pouze v systému Windows Vista a novější, by měly používat CompareStringEx.
Dalším způsobem testování jazykové rovnosti je použití lstrcmp nebo lstrcmpi, které vždy používají řazení slov. Funkce lstrcmpi volá CompareString s příznakem NORM_IGNORECASE, zatímco lstrcmp volá bez toho příznaku. Přehled použití obalovacích funkcí najdete v tématu Řetězce.
Funkce načítají lingvisticky odpovídající výsledky pro všechna národní prostředí. Očekávání uživatelů pro různá národní prostředí se mohou výrazně lišit v chování řazení, jak je znázorněno v následujících příkladech.
- Mnoho jazykových oblastí považuje ligaturu ae (æ) za stejné jako písmena ae. Islandština ho však považuje za samostatné písmeno a řadí ho za Z v abecedě.
- Kruh A (Å) se běžně řadí s pouhou diakritickou odlišností oproti A. Švédština (Švédsko) však řadí kruh A za Z v abecedním pořadí.
Funkce se snaží ověřit, zda jsou body kódu definované ve standardu Unicode kanonicky rovny řetězci ekvivalentních bodů kódu. Například kódový bod, který představuje malé písmeno "u" s přehláskou (ü), je kanonicky rovno malému písmenu "u" spojenému s přehláskou (¨). Upozorňujeme však, že kanonická ekvivalence není vždy možná.
Vzhledem k tomu, že téměř všechna data zadaná pomocí klávesnic systému Windows a editorů vstupních metod (IMEs) odpovídají normalizaci formuláře C definované ve standardu Unicode, převod příchozích dat z jiných platforem pomocí funkcí normalizace NLS Unicode poskytuje nejkonzistentnější výsledky, zejména pro jazyková nastavení, která používají tibetské písmo nebo některá moderní korejská písma Hangul. Další informace o podpoře normalizace Unicode v systému Windows Vista a novějších naleznete v tématu Použití normalizace unicode k reprezentaci řetězců.
Při porovnávání řetězců se řídí předvolbou jazyka uživatele, například při řazení položek pro seřazený ovládací prvek ListView, může aplikace provést jednu z následujících věcí:
- Volání lstrcmp nebo lstrcmpi s národním prostředím uživatele.
- Zavolejte CompareString nebo CompareStringEx, abyste definovali jazykové prostředí pro porovnání, předali další příznaky, vložili znaky null, nebo předali explicitní délky pro shodu částí řetězce.
Pokud by výsledky porovnání měly být konzistentní bez ohledu na národní prostředí, například při porovnávání načtených dat s předdefinovaným seznamem nebo interní hodnotou, měla by aplikace použít CompareString nebo CompareStringEx s parametrem Locale nastaveným na LOCALE_INVARIANT. Pro CompareStringse některé z následujících volání shoduje, i když je mystr "INLAP". V tomto případě se volání lstrcmpi závislé na národním prostředí nezdaří, pokud je aktuální národní prostředí vietnamské.
V systému Windows XP:
int iReturn = CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);
V dřívějších operačních systémech:
DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
int iReturn = CompareString(lcid, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);
Řazení řetězců ordinálně
Pro řadové řazení (nejazyčné) by vaše aplikace měly vždy používat funkci CompareStringOrdinal.
Poznámka
Tato funkce je k dispozici pouze pro systém Windows Vista a novější.
CompareStringOrdinal porovnává dva řetězce Unicode a testuje binární rovnost na rozdíl od lingvistické rovnosti. Příkladem takových nejazyčných řetězců jsou názvy souborů NTFS, proměnné prostředí a názvy mutexů, pojmenovaných kanálů nebo mailslotů. S výjimkou možnosti nerozlišování velkých a malých písmen tato funkce ignoruje všechny nebinární ekvivalence. Na rozdíl od některých dalších funkcí řazení testuje všechny body kódu pro rovnost, včetně těch, které nejsou v lingvistických schématech řazení dány žádnou váhu.
Všechny následující příkazy platí pro CompareStringOrdinal v binárních porovnáních, ale ne na CompareString, CompareStringEx, lstrcmpnebo lstrcmpi.
- Kanonické ekvivalentní sekvence v unicode, jako je LATIN SMALL LETTER A WITH RING ABOVE (U+00e5) a LATIN SMALL LETTER A + COMBINING RING ABOVE (U+0061 U+030a), nejsou stejné, i když se zobrazují identické ("å").
- Kanónicky podobné řetězce v kódování Unicode, jako jsou LATIN LETTER SMALL CAPITAL Y (U+028f) a LATIN CAPITAL LETTER Y (U+0059), které vypadají velmi podobně ("ʏ" a "Y") a liší se pouze některými speciálními váhami případů v lingvistických tabulkách, jsou považovány za zcela odlišné znaky. I když aplikace nastaví bIgnoreCase na TRUE, tyto řetězce se porovnávají jako odlišné.
- Body kódu, které jsou definovány, ale nemají žádnou jazykovou váhu řazení, jako je NAPŘÍKLAD ZERO WIDTH JOINER (U+200d), se považují za váhy bodů kódu.
- Body kódu, které jsou definovány v novějších verzích Unicode, ale nemají žádnou váhu v aktuálních lingvistických tabulkách, se považují za váhy bodů kódu.
- Body, které nejsou definovány Unicode, se považují za kódové body s vlastními vahami.
- Když aplikace nastaví bIgnoreCase na TRUE, funkce mapuje případ pomocí horní tabulky operačního systému místo informací v lingvistických tabulkách řazení. Mapování je tedy nezávislé na národním prostředí.
Další informace o kanonicky ekvivalentních sekvencích v unicode a kanonicky podobných řetězcích v Unicode naleznete v tématu Použití normalizace unicode k reprezentaci řetězců.
Seřadit kódové body
Některé body kódu Unicode nemají žádnou váhu, například ZERO WIDTH NON JOINER, U+200c. Funkce řazení záměrně vyhodnocují body kódu bez hmotnosti jako ekvivalentní, protože při řazení nemají žádnou váhu. V systému Windows Vista a novějších může aplikace tyto body kódu seřadit voláním funkcí porovnání řetězců NLS, zejména CompareStringOrdinal, pro vyhodnocení všech bodů kódu v literálu, binárním smyslu, například při ověřování hesla. V operačních systémech pre-Windows Vista by aplikace měla používat funkci modulu runtime C strcmp nebo wcscmp.
Funkce řazení ignorují diakritická znaménka, například NON SPACING BREVE, U+0306, když aplikace určuje příznak hlink_NONSPACE. Podobně tyto funkce ignorují symboly, například EQUALS SIGN, U+003d , když je zadán příznak hlink_SYMBOLS. V systému Windows Vista a novější aplikace volá CompareStringOrdinal pro vyhodnocení diakritických a symbolových bodů kódu v literálovém binárním smyslu. V operačních systémech pre-Windows Vista by aplikace měla používat strcmp nebo wcscmp.
Některé kódové body, například 0xFFFF a 0x058b, nejsou v kódu Unicode momentálně přiřazené. Tyto body kódu neobdrží žádnou váhu při řazení a nikdy by se neměly předávat funkcím řazení. Aplikace by měla použít IsNLSDefinedString k detekci jiných bodů kódu než Unicode v datovém streamu.
Poznámka
Výsledky IsNLSDefinedString se můžou lišit v závislosti na verzi Unicode předané v případě, že je znak přidán do Unicode v novější verzi a následně se přidá do tabulek řazení systému Windows. Další informace najdete v tématu Použití řazení verzí.
Řazení číslic jako čísel
Ve Windows 7 a novějších může aplikace volat CompareString, CompareStringEx, LCMapStringnebo LCMapStringEx pomocí příznaku SORT_DIGITSASNUMBERS. Tento příznak podporuje řazení, které považuje číslice za čísla, například řazení "2" před "10".
Všimněte si, že použití tohoto příznaku není vhodné pro šestnáctkové číslice, například následující.
- 01AF
1BCD
002A
12FA
AB1C
AB02
AB12
V tomto případě jsou "čísla" seřazená v pořadí, ale uživatel vnímá špatně seřazený šestnáctkový seznam.
Mapovací řetězce
Aplikace používá funkci LCMapString nebo LCMapStringEx k mapování řetězců, pokud není zadána LCMAP_SORTKEY. Mapovaný řetězec je ukončen s hodnotou null, pokud je zdrojový řetězec ukončen s hodnotou null.
Při transformaci mezi velkými a malými písmeny funkce nezaručuje, že se jeden znak bude mapovat na jeden znak. Například příznaky LCMAP_LOWERCASE a LCMAP_UPPERCASE mohou mapovat německý sharp S ("ß") na sebe. Případně může příznak LCMAP_UPPERCASE mapovat "ß" na "SS" a příznak LCMAP_LOWERCASE může mapovat "SS" na "ß". Chování závisí na verzi služby NLS.
Při transformaci mezi velkými a malými písmeny není funkce citlivá na kontext. Například zatímco příznak LCMAP_UPPERCASE správně mapuje řecké malé písmeno sigma ("σ") a řecké malé koncové písmeno sigma ("ς") na řecké velké písmeno sigma ("Σ"), příznak LCMAP_LOWERCASE vždy mapuje "Σ" na "σ," nikdy na "ς."
Ve výchozím nastavení funkce mapuje malé písmeno "i" na velké písmeno "I", i když národní prostředí parametr určuje turečtinu nebo ázerbájdžánštinu. Chcete-li toto chování přepsat pro turečtinu nebo ázerbájdžánštinu, měla by aplikace použít LCMAP_LINGUISTIC_CASING. Pokud je tento příznak zadán s odpovídajícím národním prostředím, "ı" (malé I bez tečky) je ve tvaru malého "I" (velké I bez tečky) a "i" (malé tečkované I) je ve tvaru malého "İ" (velké tečkované I).
Pokud je příznak LCMAP_HIRAGANA zadán pro mapování znaků katakana na znaky hiragana a LCMAP_FULLWIDTH není zadán, LCMapString nebo LCMapStringEx mapuje pouze znaky s plnou šířkou na hiragana. V tomto případě jsou znaky katakana o poloviční šířce umístěny do cílového řetězce bez převodu na hiraganu. Aplikace musí zadat LCMAP_FULLWIDTH pro převod katakany s poloviční šířkou na hiraganu. Důvodem tohoto omezení je, že všechny znaky hiragana jsou znaky s plnou šířkou.
Pokud aplikace potřebuje odstranit znaky ze zdrojového řetězce, může volat funkci mapování s nastavenými příznaky NORM_IGNORESYMBOLS a NORM_IGNORENONSPACE a všechny ostatní příznaky se vymažou. Pokud to aplikace provede se zdrojovým řetězcem, který není ukončen s hodnotou null, je možné, že funkce vrátí prázdný řetězec a nevrátí chybu.
Vytvoření klíčů řazení
Když aplikace určuje LCMAP_SORTKEY, LCMapString nebo LCMapStringEx vygeneruje klíč řazení, binární pole bajtů hodnot. Klíč řazení není skutečný řetězec a jeho hodnoty představují chování řazení zdrojového řetězce, ale nejsou smysluplnými hodnotami pro zobrazení.
Poznámka
Funkce ignoruje arabské kašidy během generování klíče řazení. Pokud aplikace zavolá funkci k vytvoření klíče řazení pro řetězec obsahující arabský kashida, funkce nevytvoří žádnou hodnotu klíče řazení.
Klíč řazení může obsahovat lichý počet bajtů. Příznak LCMAP_BYTEREV obrátí výhradně sudý počet bajtů. Poslední bajt (lichý) v klíči řazení není obrácený. Pokud je ukončovací bajt 0x00 na liché pozici, zůstane posledním bajtem v klíči řazení. Pokud je ukončovací 0x00 bajt rovnoměrně umístěný bajt, vymění pozice s bajtem, který mu předchází.
Při generování klíče řazení funkce zachází se spojovníkem a apostrofem jinak než s ostatními interpunkčními symboly, aby se slova, jako například "coop" a "co-op", držela pohromadě v seznamu. Všechny jiné symboly interpunkce než spojovník a apostrof se seřadí před alfanumerické znaky. Aplikace toto chování může změnit nastavením příznaku SORT_STRINGSORT, jak je popsáno v Funkce řazení.
Při použití v memcmp, klíč řazení vytvoří stejné pořadí jako při použití zdrojového řetězce v CompareString nebo CompareStringEx. Funkce memcmp by měla být použita místo strcmp, protože klíč řazení může obsahovat vložené bajty null.
Použití verzování řazení
Tabulka řazení má dvě čísla, která identifikují její verzi: definovanou verzi a verzi služby NLS. Obě čísla jsou hodnoty DWORD, které se skládají z hlavní hodnoty a menší hodnoty. První bajt hodnoty je vyhrazen, další dva bajty představují hlavní verzi a poslední bajt představuje podverzi. V šestnáctkovém formátu je vzor 0xRRMMMMmm, kde R se rovná rezervovanému, M se rovná hlavní verzi a m dílčí verzi. Například hlavní verze 3 s vedlejší verzí 4 je reprezentována jako 0x304.
Definovaná verze identifikuje repertoár kódových bodů a je stejná pro všechna jazyková nastavení. Hlavní verze se zvyšuje, aby označila změny stávajících kódových bodů. Podverze inkrementuje, že byly přidány body kódu, ale nebyly změněny žádné dříve existující body kódu.
Verze služby NLS je specifická pro identifikátor nastavení místního prostředí nebo název nastavení místního prostředí a sleduje změny vážení bodů kódu pro příslušné místní prostředí. Hlavní verze se zvýší, když se změní váhy pro body kódu, které už byly seřazené. Podverze se zvýší, když jsou nové body kódu přiřazeny váhy, ale všechny ostatní dříve seřazené váhy bodů kódu zůstanou beze změny.
Poznámka
U hlavní verze se změní jeden nebo více bodů kódu, aby aplikace musela znovu indexovat všechna data, aby byla porovnání platná. V případě menší verze se nic nepřesune, ale přidají se body kódu. Pro tento typ verze musí aplikace pouze znovu indexovat řetězce s dříve neseřazenými hodnotami.
Důležitý
Hlavní verze byla ve Windows 8 změněna. Data vytvořená v dřívějších verzích Windows musí být znovu indexována.
Definované verze i verze NLS platí pro řaditelné body kódu načtené pomocí funkce LCMapString nebo funkce LCMapStringEx s příznakem LCMAP_SORTKEY, a také použité funkcemi CompareString, CompareStringEx, FindNLSString, a FindNLSStringEx. Pokud je jeden nebo více kódových bodů v řetězci neseřaditelných, vrátí funkce IsNLSDefinedStringFALSE, když je řetězec předán jako parametr.
Aplikace může volat GetNLSVersion nebo GetNLSVersionEx k tomu, aby načetla jak definovanou verzi, tak verzi NLS pro tabulku řazení.
Indexování databáze
Z důvodů výkonu by aplikace měla při indexování databáze postupovat podle tohoto postupu.
Správné indexování databáze
- Pro každou funkci uložte verzi NLS, klíče řazení této verze a indikátor použitelnosti pro řazení každého indexovaného řetězce.
- Při přírůstku podverze znovu indexujte dříve neseřazené řetězce. Řetězce ovlivněné v této aktualizaci by měly být omezeny na řetězce, pro které IsNLSDefinedString dříve vrátil FALSE.
- Když se hlavní verze zvýší, znovu indexujte všechny řetězce, protože aktualizované váhy můžou změnit chování libovolného řetězce. Hlavní verze jsou velmi zřídka vydávány.
K problémům s indexováním databáze může dojít z následujících důvodů:
- Pozdější operační systém může definovat body kódu, které nejsou definovány pro starší operační systém, a tím změnit řazení.
- Body kódu můžou mít různé váhy řazení v různých operačních systémech kvůli opravám v podpoře jazyka.
K minimalizaci nutnosti opětovného indexování databáze v těchto případech může aplikace použít IsNLSDefinedString odlišit definované od nedefinovaných řetězců, aby aplikace mohl odmítnout řetězce s nedefinovanými body kódu. Použití GetNLSVersion nebo GetNLSVersionEx umožňuje aplikaci určit, jestli změna služby NLS ovlivňuje národní prostředí používané pro konkrétní tabulku indexu. Pokud změna nemá žádný vliv na národní prostředí, aplikace nemusí tabulku znovu indexovat.
Příklady
Následující tabulka znázorňuje účinky určitých flagů používaných s funkcemi řazení. V každém případě výběr příznaků určuje, zda jsou dva různé znaky považovány za stejné pro účely řazení.
Postava 1 | Znak 2 | Výchozí | NORM_IGNOREWIDTH | NORM_IGNOREKANA | NORM_IGNOREWIDTH| NORMIGNOREKANA |
---|---|---|---|---|---|
"あ" U+3042 HIRAGANA písmeno A |
"ガ" U+30A2 KATAKANA LETTER A |
Nerovný | Nerovný | Rovný | Rovný |
"オ" U+FF75 POLOŠÍŘKOVÝ ZNAK KATAKANA O |
"オ" U+30AA KATAKANA LETTER O |
Nerovný | Rovný | Nerovný | Rovný |
"B" VELKÉ KAPITÁLOVÉ PÍSMENO LATINKY B U+FF22 celé šířky |
"B" VELKÉ PÍSMENO LATINSKÉ B U+0042 |
Nerovný | Rovný | Nerovný | Rovný |
Související témata