Gestione dell'ordinamento nelle applicazioni
Alcune applicazioni, ad esempio Microsoft Active Directory, Microsoft Exchange e Microsoft Access, gestiscono un database ordinabile di stringhe locali e di lingua indicizzate in base al nome (stringa UTF-16) e ai pesi di ordinamento associati.
L'ordinamento è in genere intuitivo per gli utenti nelle proprie impostazioni locali. Tuttavia, può essere non intuitivo per gli sviluppatori di applicazioni. Questo argomento illustra le considerazioni per la gestione dell'ordinamento nelle applicazioni. L'ordinamento può essere linguistico o ordinale (non linguistico).
Funzioni di ordinamento
È possibile usare un'ampia gamma di funzioni di ordinamento nelle applicazioni:
- Funzioni di confronto tra stringhe NLS. Esempi sono CompareString e CompareStringEx, CompareStringOrdinal, LCMapString, LCMapStringEx, FindNLSString, FindNLSStringEx e FindStringOrdinal. Vedere Considerazioni sulla sicurezza: Funzionalità internazionali per una descrizione dei problemi di sicurezza correlati alle funzioni di confronto tra stringhe.
- Funzioni wrapper che chiamano internamente le funzioni di confronto tra stringhe. Le funzioni più comuni sono lstrcmp e lstrcmpi, che chiamano CompareString.
In genere, le funzioni di ordinamento valutano i caratteri delle stringhe in base al carattere. Tuttavia, molte lingue hanno elementi a più caratteri, ad esempio la coppia di due caratteri "CH" in spagnolo tradizionale. CompareString e CompareStringEx usano l'identificatore o il nome delle impostazioni locali forniti dall'applicazione per identificare più elementi di caratteri. Al contrario, lstrcmp e lstrcmpi usano le impostazioni locali dell'utente.
Un altro esempio è vietnamita, che contiene molti elementi a due caratteri, ad esempio le forme maiuscole, maiuscole e minuscole valide di "GI", che sono rispettivamente "GI, "Gi" e "gi". Una di queste forme viene considerata come un singolo elemento di ordinamento e, se la combinazione di maiuscole e minuscole viene ignorata, viene confrontata come uguale. Tuttavia, poiché "gI" non è valido come singolo elemento, CompareString, CompareStringEx, lstrcmp e lstrcmpi considerano "gI" come due elementi separati.
Le funzioni CompareString, CompareStringEx, lstrcmp, lstrcmpi, LCMapString, LCMapStringEx, FindNLSString e FindNLSStringEx per impostazione predefinita usano una tecnica "word sort". Per questo tipo di ordinamento, tutti i segni di punteggiatura e altri caratteri non alfanumerici, ad eccezione del trattino e dell'apostrofo, vengono prima di qualsiasi carattere alfanumerico. Il trattino e l'apostrofo vengono trattati in modo diverso dagli altri caratteri non alfanumerici per garantire che le parole come "coop" e "co-op" rimangano unite in un elenco ordinato.
Anziché un ordinamento di parole, l'applicazione può richiedere una tecnica di "ordinamento stringa" dalle funzioni di ordinamento specificando il flag SORT_STRINGSORT. Un ordinamento stringa tratta il trattino e l'apostrofo esattamente come qualsiasi altro carattere non alfanumerico. Le posizioni nella sequenza di ordinamento sono precedenti ai caratteri alfanumerici.
Nella tabella seguente vengono confrontati i risultati di un ordinamento di parole con i risultati di un ordinamento di stringa.
Ordinamento Word | Ordinamento stringhe |
---|---|
Billetta | bill's |
Bollette | Billetta |
bill's | Bollette |
non può | Non |
non posso | non può |
Non | non posso |
con | Cooperativa |
Coop | con |
Cooperativa | Coop |
Ordinare stringhe in modo linguistico
Le funzioni CompareString e CompareStringEx testano l'uguaglianza linguistica. Le applicazioni devono usare queste funzioni con le impostazioni locali corrette per l'ordinamento delle stringhe in modo linguistico.
Nota
Per la compatibilità con Unicode, un'applicazione deve preferire CompareStringEx o la versione Unicode di CompareString. Un altro motivo per cui si preferisce CompareStringEx è che Microsoft sta eseguendo la migrazione all'uso dei nomi delle impostazioni locali anziché degli identificatori delle impostazioni locali per le nuove impostazioni locali, per motivi di interoperabilità. Qualsiasi applicazione eseguita solo in Windows Vista e versioni successive deve usare CompareStringEx.
Un altro modo per testare l'uguaglianza linguistica consiste nell'usare lstrcmp o lstrcmpi, che usa sempre un ordinamento di parole. La funzione lstrcmpi chiama CompareString con il flag NORM_IGNORECASE, mentre lstrcmp lo chiama senza tale flag. Per una panoramica dell'uso delle funzioni wrapper, vedere Stringhe.
Le funzioni recuperano i risultati linguistici appropriati per tutte le impostazioni locali. Le aspettative degli utenti per impostazioni locali diverse possono differire in modo significativo nel comportamento di ordinamento, come illustrato negli esempi seguenti.
- Molte impostazioni locali equivalgono alla legatura ae (æ) con le lettere ae. Tuttavia, islandese (Islanda) considera una lettera separata e la inserisce dopo Z nella sequenza di ordinamento.
- L'anello A (Å) ordina normalmente con una semplice differenza diacritica da A. Tuttavia, svedese (Svezia) posiziona l'anello A dopo Z nella sequenza di ordinamento.
Le funzioni tentano di verificare rigorosamente che i punti di codice definiti nello standard Unicode siano canonicamente uguali a una stringa di punti di codice equivalenti. Ad esempio, il punto di codice che rappresenta una "u" minuscola con una dieresi (ü) è canonicamente uguale a una "u" minuscola combinata con la dieresi ( ̈). Si noti, tuttavia, che l'equivalenza canonica non è sempre possibile.
Poiché quasi tutti i dati immessi usando le tastiere di Windows e gli editor di metodi di input (IMEs) sono conformi al formato C di normalizzazione definito nello standard Unicode, convertendo i dati in ingresso da altre piattaforme usando le funzioni di normalizzazione Unicode NLS fornisce risultati più coerenti, soprattutto per le impostazioni locali che usano lo script tibetano o lo script Hangul per hangul moderno. Per altre informazioni sul supporto della normalizzazione Unicode in Windows Vista e versioni successive, vedere Using Unicode Normalization to Represent Strings .For more information on Unicode normalization in Windows Vista and later, see Using Unicode Normalization to Represent Strings.
Quando il confronto tra stringhe segue la preferenza di lingua dell'utente, ad esempio quando si ordinano elementi per un controllo ListView ordinato, l'applicazione può eseguire una delle operazioni seguenti:
- Chiamare lstrcmp o lstrcmpi con le impostazioni locali dell'utente.
- Chiamare CompareString o CompareStringEx per definire le impostazioni locali per il confronto, passare flag aggiuntivi, incorporare caratteri Null o passare lunghezze esplicite in modo che corrispondano a parti di una stringa.
Quando i risultati del confronto devono essere coerenti indipendentemente dalle impostazioni locali, ad esempio, quando si confrontano i dati recuperati con un elenco predefinito o un valore interno, l'applicazione deve usare CompareString o CompareStringEx con il parametro Locale impostato su LOCALE_INVARIANT. Per CompareString, una delle chiamate seguenti corrisponde anche se mystr è "INLAP". In questo caso, una chiamata con distinzione delle impostazioni locali a lstrcmpi avrà esito negativo se le impostazioni locali correnti sono vietnamite.
In Windows XP:
int iReturn = CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);
Nei sistemi operativi precedenti:
DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
int iReturn = CompareString(lcid, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);
Ordina stringhe ordinali
Per l'ordinamento ordinale (non linguistico), le applicazioni devono sempre usare la funzione CompareStringOrdinal .
Nota
Questa funzione è disponibile solo per Windows Vista e versioni successive.
CompareStringOrdinal confronta due stringhe Unicode per verificare l'uguaglianza binaria, anziché l'uguaglianza linguistica. Esempi di tali stringhe non linguistiche sono nomi di file NTFS, variabili di ambiente e nomi di mutex, named pipe o mailslot. Fatta eccezione per l'opzione di distinzione tra maiuscole e minuscole, questa funzione ignora tutte le equivalenze non binarie. A differenza di altre funzioni di ordinamento, testa tutti i punti di codice per verificarne l'uguaglianza, inclusi quelli che non hanno alcun peso negli schemi di ordinamento linguistico.
Tutte le istruzioni seguenti si applicano a CompareStringOrdinal nei confronti binari, ma non a CompareString, CompareStringEx, lstrcmp o lstrcmpi.
- Le sequenze equivalenti canoniche in Unicode, ad esempio LA LETTERA MINUSCOLA LATINA A CON ANELLO SOPRA (U+00e5) e LA LETTERA MINUSCOLA IN ALFABETO LATINO A + COMBINAZIONE SOPRA (U+0061 U+030a), non sono uguali anche se appaiono identici ("å").
- Le stringhe in formato canonico sono simili in Unicode, ad esempio LETTERE LATINE MINUSCOLE Y (U+028f) e MAIUSCOLE LATINE Y (U+0059), che sembrano molto simili ("ʏ" e "Y") e variano solo in base ad alcuni pesi maiuscoli speciali nelle tabelle linguistiche, sono considerati caratteri completamente diversi. Anche se l'applicazione imposta bIgnoreCase su TRUE, queste stringhe vengono confrontate come diverse.
- I punti di codice definiti ma senza peso di ordinamento linguistico, ad esempio ZERO WIDTH JOINER (U+200d), vengono considerati come con i pesi del punto di codice.
- I punti di codice definiti nelle versioni successive di Unicode, ma non hanno alcun peso nelle tabelle linguistiche correnti, vengono considerati come ponderati per i punti di codice.
- I punti di codice non definiti da Unicode vengono considerati come con i relativi pesi del punto di codice.
- Quando l'applicazione imposta bIgnoreCase su TRUE, la funzione esegue il mapping tra maiuscole e minuscole usando la tabella di ordinamento superiore del sistema operativo anziché le informazioni nelle tabelle di ordinamento linguistico. Il mapping è quindi indipendente dalle impostazioni locali.
Per altre informazioni sulle sequenze canoniche equivalenti in Stringhe Unicode e in modo canonico in Unicode, vedere Using Unicode Normalization to Represent Strings.For more information about canonically equivalent sequences in Unicode and canonically similar strings in Unicode, see Using Unicode Normalization to Represent Strings.
Ordinare i punti di codice
Alcuni punti di codice Unicode non hanno peso, ad esempio ZERO WIDTH NON JOINER, U+200c. Le funzioni di ordinamento valutano intenzionalmente i punti di codice senza peso come equivalenti perché non hanno peso nell'ordinamento. In Windows Vista e versioni successive, l'applicazione può ordinare questi punti di codice chiamando le funzioni di confronto tra stringhe NLS, in particolare CompareStringOrdinal, per la valutazione di tutti i punti di codice in un senso letterale, binario, ad esempio, nella convalida della password. Nei sistemi operativi pre-Windows Vista, l'applicazione deve usare la funzione di runtime C strcmp o wcscmp.
Le funzioni di ordinamento ignorano i segni diacritici, ad esempio NON SPAZIATURA BREVE, U+0306, quando l'applicazione specifica il flag hlink_NONSPACE. Analogamente, queste funzioni ignorano i simboli, ad esempio EQUALS SIGN, U+003d , quando viene specificato il flag hlink_SYMBOLS. In Windows Vista e versioni successive l'applicazione chiama CompareStringOrdinal per la valutazione dei segni diacritici e dei punti di codice dei simboli in un senso binario letterale. Nei sistemi operativi pre-Windows Vista, l'applicazione deve usare strcmp o wcscmp.
Alcuni punti di codice, ad esempio 0xFFFF e 0x058b, non sono attualmente assegnati in Unicode. Questi punti di codice non ricevono alcun peso nell'ordinamento e non devono mai essere passati alle funzioni di ordinamento. L'applicazione deve usare IsNLSDefinedString per rilevare punti di codice non Unicode in un flusso di dati.
Nota
I risultati di IsNLSDefinedString possono variare a seconda della versione Unicode passata se un carattere viene aggiunto a Unicode in una versione successiva e successivamente viene aggiunto alle tabelle di ordinamento di Windows. Per altre informazioni, vedere Usare il controllo delle versioni di ordinamento.
Ordina cifre come numeri
In Windows 7 e versioni successive l'applicazione può chiamare CompareString, CompareStringEx, LCMapString o LCMapStringEx usando il flag SORT_DIGITSASNUMBERS. Questo flag supporta l'ordinamento che considera le cifre come numeri, ad esempio l'ordinamento di "2" prima di "10".
Si noti che l'uso di questo flag non è appropriato per le cifre esadecimali, ad esempio quanto segue.
- 01AF
1BCD
002A
12FA
AB1C
AB02
AB12
In questo caso i "numeri" vengono ordinati in ordine, ma l'utente percepisce un elenco esadecimale non corretto.
Stringhe mappa
L'applicazione usa la funzione LCMapString o LCMapStringEx per eseguire il mapping delle stringhe, se LCMAP_SORTKEY non è specificato. Una stringa mappata viene terminata con null se la stringa di origine è con terminazione Null.
Quando si trasforma tra maiuscole e minuscole, la funzione non garantisce che un singolo carattere venga mappato a un singolo carattere. Ad esempio, i flag LCMAP_LOWERCASE e LCMAP_UPPERCASE possono mappare il tedesco Sharp S ("ß") a se stesso. In alternativa, il flag LCMAP_UPPERCASE può eseguire il mapping di "ß" a "SS" e il flag LCMAP_LOWERCASE può mappare "SS" a "ß". Il comportamento dipende dalla versione NLS.
Quando si trasforma tra maiuscole e minuscole, la funzione non è sensibile al contesto. Ad esempio, mentre il flag LCMAP_UPPERCASE esegue correttamente il mapping di sigma minuscolo greco ("σ") e greco minuscolo sigma ("Ο") a sigma maiuscolo greco ("Σ"), il flag LCMAP_LOWERCASE esegue sempre il mapping di "Σ" a "σ", mai a "Ο".
Per impostazione predefinita, la funzione esegue il mapping tra "i" minuscolo e "I" maiuscolo, anche quando il parametro Locale specifica turco o azero. Per eseguire l'override di questo comportamento per turco o azero, l'applicazione deve specificare LCMAP_LINGUISTIC_CASING. Se questo flag viene specificato con le impostazioni locali appropriate, "ı" (i minuscolo senza punti) è la forma minuscola di "I" (i maiuscolo senza punti) e "i" (minuscolo punteggiato I) è la forma minuscola di "İ" (maiuscola punteggiata I).
Se il flag di LCMAP_HIRAGANA viene specificato per eseguire il mapping dei caratteri katakana ai caratteri hiragana e LCMAP_FULLWIDTH non è specificato, LCMapString o LCMapStringEx esegue il mapping dei caratteri a larghezza intera solo a hiragana. In questo caso, tutti i caratteri katakana a metà larghezza vengono inseriti come nella stringa di destinazione, senza mapping a hiragana. L'applicazione deve specificare LCMAP_FULLWIDTH per eseguire il mapping dei caratteri katakana a metà larghezza a hiragana. Il motivo di questa restrizione è che tutti i caratteri hiragana sono caratteri a larghezza intera.
Se l'applicazione deve rimuovere caratteri dalla stringa di origine, può chiamare la funzione di mapping con i flag NORM_IGNORESYMBOLS e NORM_IGNORENONSPACE impostati e tutti gli altri flag deselezionati. Se l'applicazione esegue questa operazione con una stringa di origine non con terminazione Null, è possibile che la funzione restituisca una stringa vuota e non restituisca un errore.
Creare chiavi di ordinamento
Quando l'applicazione specifica LCMAP_SORTKEY, LCMapString o LCMapStringEx genera una chiave di ordinamento, una matrice binaria di valori di byte. La chiave di ordinamento non è una stringa vera e i relativi valori rappresentano il comportamento di ordinamento della stringa di origine, ma non sono valori di visualizzazione significativi.
Nota
La funzione ignora la kashida araba durante la generazione di una chiave di ordinamento. Se un'applicazione chiama la funzione per creare una chiave di ordinamento per una stringa contenente un kashida arabo, la funzione non crea alcun valore di chiave di ordinamento.
La chiave di ordinamento può contenere un numero dispari di byte. Il flag LCMAP_BYTEREV inverte solo un numero pari di byte. L'ultimo byte (dispari posizionato) nella chiave di ordinamento non viene invertito. Se il byte di terminazione 0x00 è un byte dispari, rimane l'ultimo byte nella chiave di ordinamento. Se la terminazione 0x00 byte è un byte posizionato uniforme, scambia posizioni con il byte che lo precede.
Quando si genera la chiave di ordinamento, la funzione tratta il trattino e l'apostrofo in modo diverso da altri simboli di punteggiatura, in modo che le parole come "coop" e "co-op" rimangano unite in un elenco. Tutti i simboli di punteggiatura diversi dal trattino e dall'apostrofo vengono ordinati prima dei caratteri alfanumerici. L'applicazione può modificare questo comportamento impostando il flag SORT_STRINGSORT, come descritto in Funzioni di ordinamento.
Se usato in memcmp, la chiave di ordinamento produce lo stesso ordine di quando viene usata la stringa di origine in CompareString o CompareStringEx. La funzione memcmp deve essere usata invece di strcmp, perché la chiave di ordinamento può avere byte Null incorporati.
Usare il controllo delle versioni di ordinamento
Una tabella di ordinamento contiene due numeri che ne identificano la versione: la versione definita e la versione NLS. Entrambi i numeri sono valori DWORD, costituiti da un valore principale e da un valore secondario. Il primo byte di un valore è riservato, i due byte successivi rappresentano la versione principale e l'ultimo byte rappresenta la versione secondaria. In termini esadecimali, il modello è 0xRRMMMMmm, dove R è uguale a Reserved, M uguale a major e m è minore. Ad esempio, una versione principale di 3 con una versione secondaria di 4 è rappresentata come 0x304.
La versione definita identifica il repertorio dei punti di codice ed è la stessa per tutte le impostazioni locali. Incrementi della versione principale per indicare le modifiche apportate ai punti di codice esistenti. Incrementi di versione secondaria per indicare che sono stati aggiunti punti di codice, ma che non sono stati modificati punti di codice esistenti in precedenza.
La versione NLS è specifica per un identificatore delle impostazioni locali o un nome delle impostazioni locali e tiene traccia delle modifiche apportate ai pesi del punto di codice per le impostazioni locali interessate. La versione principale viene incrementata quando i pesi vengono modificati per i punti di codice già ordinabili. La versione secondaria aumenta quando vengono assegnati nuovi punti di codice, ma tutti gli altri pesi dei punti di codice ordinabili in precedenza rimangono invariati.
Nota
Per una versione principale, uno o più punti di codice vengono modificati in modo che l'applicazione debba ri-indicizzare tutti i dati per poter essere validi per i confronti. Per una versione secondaria, non viene spostato alcun elemento, ma vengono aggiunti punti di codice. Per questo tipo di versione, l'applicazione deve solo indicizzare nuovamente le stringhe con valori precedentemente non interrompibili.
Importante
La versione principale è stata modificata in Windows 8. I dati creati nelle versioni precedenti di Windows devono essere indicizzati nuovamente.
Entrambe le versioni definite e NLS si applicano ai punti di codice ordinabili recuperati usando la funzione LCMapString o LCMapStringEx con il flag LCMAP_SORTKEY e usati anche dalle funzioni CompareString, CompareStringEx, FindNLSString e FindNLSStringEx . Se uno o più punti di codice in una stringa non sono disponibili, la funzione IsNLSDefinedString restituisce FALSE quando tale stringa viene passata come parametro.
L'applicazione può chiamare GetNLSVersion o GetNLSVersionEx per recuperare sia la versione definita che la versione NLS per una tabella di ordinamento.
Indicizzare il database
Per motivi di prestazioni, l'applicazione deve seguire questa procedura durante l'indicizzazione del database.
Per indicizzare correttamente il database
- Per ogni funzione, archiviare la versione NLS, le chiavi di ordinamento di tale versione e un'indicazione di ordinabilità per ogni stringa indicizzata.
- Quando la versione secondaria viene incrementata, reindicizzazione delle stringhe precedentemente nonortabili. Le stringhe interessate in questo aggiornamento devono essere limitate a quelle per le quali IsNLSDefinedString ha precedentemente restituito FALSE.
- Quando la versione principale viene incrementata, ri indicizzare tutte le stringhe perché i pesi aggiornati potrebbero modificare il comportamento di qualsiasi stringa. Le versioni principali sono molto poco frequenti.
I problemi di indicizzazione del database possono verificarsi per i motivi seguenti:
- Un sistema operativo successivo può definire punti di codice non definiti per un sistema operativo precedente, modificando così l'ordinamento.
- I punti di codice possono avere pesi di ordinamento diversi in sistemi operativi diversi, a causa delle correzioni nel supporto del linguaggio.
Per ridurre al minimo la necessità di reindicizzazione del database in queste circostanze, l'applicazione può usare IsNLSDefinedString per distinguere le stringhe definite da stringhe non definite in modo che l'applicazione possa rifiutare stringhe con punti di codice non definiti. L'uso di GetNLSVersion o GetNLSVersionEx consente all'applicazione di determinare se una modifica NLS influisce sulle impostazioni locali utilizzate per una tabella di indice specifica. Se la modifica non ha alcun effetto sulle impostazioni locali, l'applicazione non deve reindicizzazione della tabella.
Esempio
La tabella seguente illustra gli effetti di determinati flag usati con le funzioni di ordinamento. In ogni caso, la selezione dei flag determina se due caratteri diversi vengono considerati uguali a scopo di ordinamento.
Carattere 1 | Carattere 2 | Predefinito | NORM_IGNOREWIDTH | NORM_IGNOREKANA | NORM_IGNOREWIDTH| NORMIGNOREKANA |
---|---|---|---|---|---|
"あ" U+3042 HIRAGANA LETTERA A |
"ガ" U+30A2 LETTERA KATAKANA A |
Disuguale | Disuguale | Uguale a | Uguale a |
"オ" U+FF75 HALFWIDTH KATAKANA LETTER O |
"オ" U+30AA LETTERA KATAKANA O |
Disuguale | Uguale a | Disuguale | Uguale a |
"B" U+FF22 FULLWIDTH LATIN LETTERA B |
"B" U+0042 LETTERA MAIUSCOLA LATINA B |
Disuguale | Uguale a | Disuguale | Uguale a |
Argomenti correlati