Control de la ordenación en las aplicaciones

Algunas aplicaciones, como Microsoft Active Directory, Microsoft Exchange y Microsoft Access, mantienen una base de datos ordenable de cadenas de idioma y configuración regional indexadas por nombre (cadena UTF-16) y sus ponderaciones de ordenación asociadas.

La ordenación suele ser intuitiva para los usuarios en sus propias configuraciones regionales. Sin embargo, puede ser no intuitivo para los desarrolladores de aplicaciones. En este tema se describen las consideraciones para controlar la ordenación en las aplicaciones. La ordenación puede ser lingüística o ordinal (no lingüística).

Funciones de ordenación

Puede usar una variedad de funciones de ordenación en las aplicaciones:

Normalmente, las funciones de ordenación evalúan los caracteres de cadena por carácter. Sin embargo, muchos idiomas tienen elementos de varios caracteres, como el par de dos caracteres "CH" en español tradicional. CompareString y CompareStringEx usan el identificador o el nombre de configuración regional proporcionados por la aplicación para identificar elementos de varios caracteres. Por el contrario, lstrcmp y lstrcmpi usan la configuración regional del usuario.

Otro ejemplo es vietnamita, que contiene muchos elementos de dos caracteres, como las formas válidas en mayúsculas, mayúsculas y minúsculas de "GI", que son "GI, "Gi" y "gi", respectivamente. Cualquiera de estos formularios se trata como un elemento de ordenación único y, si se omite el uso de mayúsculas y minúsculas, se compara como igual. Sin embargo, dado que "gI" no es válido como un solo elemento, CompareString, CompareStringEx, lstrcmp y lstrcmpi tratan "gI" como dos elementos independientes.

Las funciones CompareString, CompareStringEx, lstrcmp, lstrcmpi, LCMapString, LCMapStringEx, FindNLSString y FindNLSStringEx usan de forma predeterminada una técnica de "ordenación de palabras". Para este tipo de ordenación, todas las marcas de puntuación y otros caracteres nonalphanumeric, excepto para el guión y el apóstrofo, vienen antes de cualquier carácter alfanumérico. El guión y el apóstrofo se tratan de forma diferente de los otros caracteres nonalphanumeric para asegurarse de que las palabras como "coop" y "co-op" permanecen juntas en una lista ordenada.

En lugar de una ordenación de palabras, la aplicación puede solicitar una técnica de "ordenación de cadenas" a partir de las funciones de ordenación especificando la marca SORT_STRINGSORT. Una ordenación de cadena trata el guión y el apóstrofo como cualquier otro carácter nonalphanumeric. Sus posiciones en la secuencia de ordenación son anteriores a los caracteres alfanuméricos.

En la tabla siguiente se comparan los resultados de una ordenación de palabras con los resultados de una ordenación de cadena.

Ordenación de Word Ordenación de cadenas
Billete bill's
Cuentas Billete
bill's Cuentas
no puede No
hipocresía no puede
No hipocresía
con cooperación
Coop con
cooperación Coop

 

Ordenar cadenas lingüísticamente

Las funciones CompareString y CompareStringEx comprueban la igualdad lingüística. Las aplicaciones deben usar estas funciones con la configuración regional correcta para ordenar cadenas lingüísticamente.

Nota

Para la compatibilidad con Unicode, una aplicación debe preferir CompareStringEx o la versión Unicode de CompareString. Otro motivo para preferir CompareStringEx es que Microsoft está migrando hacia el uso de nombres de configuración regional en lugar de identificadores de configuración regional para nuevas configuraciones regionales, por motivos de interoperabilidad. Cualquier aplicación que se ejecute solo en Windows Vista y versiones posteriores debe usar CompareStringEx.

 

Otra forma de probar la igualdad lingüística es usar lstrcmp o lstrcmpi, que siempre usan una ordenación de palabras. La función lstrcmpi llama a CompareString con la marca NORM_IGNORECASE, mientras que lstrcmp la llama sin esa marca. Para obtener información general sobre el uso de las funciones contenedoras, consulte Cadenas.

Las funciones recuperan los resultados lingüísticos adecuados para todas las configuraciones regionales. Las expectativas del usuario para diferentes configuraciones regionales pueden diferir significativamente en el comportamiento de ordenación, como se muestra en los ejemplos siguientes.

  • Muchas configuraciones regionales equivalen a la ligadura ae (æ) con las letras ae. Sin embargo, islandés (Islandia) lo considera una letra independiente y la coloca después de Z en la secuencia de ordenación.
  • El Anillo A (Å) normalmente se ordena con simplemente una diferencia diacrítica de A. Sin embargo, sueco (Suecia) coloca el Anillo A después de Z en la secuencia de ordenación.

Las funciones intentan comprobar rigurosamente que los puntos de código definidos en el estándar Unicode son canónicamente iguales a una cadena de puntos de código equivalentes. Por ejemplo, el punto de código que representa una "u" minúscula con una dieresis (ü) es canónicamente igual a una "u" minúscula combinada con la dieresis ( ́). Sin embargo, tenga en cuenta que la equivalencia canónica no siempre es posible.

Dado que casi todos los datos especificados con teclados de Windows y editores de métodos de entrada (IME) se ajustan a la normalización C definida en el estándar Unicode, la conversión de datos entrantes de otras plataformas mediante las funciones de normalización Unicode NLS proporciona resultados más coherentes, especialmente para las configuraciones regionales que usan el script tibetano o el script Hangul para hangul moderno. Para obtener más información sobre la compatibilidad con la normalización Unicode en Windows Vista y versiones posteriores, vea Usar la normalización Unicode para representar cadenas.

Cuando la comparación de cadenas sigue la preferencia de idioma del usuario, por ejemplo, al ordenar elementos para un control ListView ordenado, la aplicación puede realizar una de las siguientes acciones:

  • Llame a lstrcmp o lstrcmpi con la configuración regional del usuario.
  • Llame a CompareString o CompareStringEx para definir una configuración regional para la comparación, pasar marcas adicionales, insertar caracteres NULL o pasar longitudes explícitas para que coincidan con partes de una cadena.

Cuando los resultados de la comparación deben ser coherentes independientemente de la configuración regional, por ejemplo, al comparar los datos recuperados con una lista predefinida o un valor interno, la aplicación debe usar CompareString o CompareStringEx con el parámetro Locale establecido en LOCALE_INVARIANT. Para CompareString, cualquiera de las siguientes llamadas coincidirá incluso si mystr es "INLAP". En este caso, se producirá un error en una llamada sensible a la configuración regional a lstrcmpi si la configuración regional actual es vietnamita.

En Windows XP:

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

En sistemas operativos anteriores:

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

Ordenar cadenas ordinally

Para la ordenación ordinal (no lingüística), las aplicaciones siempre deben usar la función CompareStringOrdinal .

Nota

Esta función solo está disponible para Windows Vista y versiones posteriores.

 

CompareStringOrdinal compara dos cadenas Unicode para probar la igualdad binaria, en lugar de la igualdad lingüística. Algunos ejemplos de estas cadenas no lingüísticas son nombres de archivo NTFS, variables de entorno y nombres de exclusión mutua, canalizaciones con nombre o gráficos de correo. Excepto por la opción de insensibilidad entre mayúsculas y minúsculas, esta función ignora todas las equivalencias no binarias. A diferencia de otras funciones de ordenación, prueba todos los puntos de código para la igualdad, incluidos los que no tienen ningún peso en los esquemas de ordenación lingüística.

Todas las siguientes instrucciones se aplican a CompareStringOrdinal en comparaciones binarias, pero no a CompareString, CompareStringEx, lstrcmp o lstrcmpi.

  • Secuencias canónicamente equivalentes en Unicode, como LATIN SMALL LETTER A WITH RING ABOVE (U+00e5) y LATIN SMALL LETTER A + COMBINING RING ABOVE (U+0061 U+030a), no son iguales aunque aparezcan idénticas ("å").
  • Las cadenas canónicamente similares en Unicode, como LATIN LETTER SMALL CAPITAL Y (U+028f) y LATIN CAPITAL LETTER Y (U+0059), que tienen un aspecto muy similar ("ʏ" y "Y") y varían solo por algunos pesos de mayúsculas y minúsculas especiales en las tablas lingüísticas, se consideran caracteres completamente diferentes. Incluso si la aplicación establece bIgnoreCase en TRUE, estas cadenas se comparan como diferentes.
  • Los puntos de código definidos pero que no tienen ningún peso de ordenación lingüístico, como ZERO WIDTH JOINER (U+200d), se tratan como tener sus pesos de punto de código.
  • Los puntos de código definidos en versiones posteriores de Unicode, pero que no tienen ningún peso en las tablas lingüísticas actuales se tratan como tener sus pesos de punto de código.
  • Los puntos de código no definidos por Unicode se tratan como tener sus pesos de punto de código.
  • Cuando la aplicación establece bIgnoreCase en TRUE, la función asigna mayúsculas de minúsculas mediante la tabla de mayúsculas del sistema operativo, en lugar de la información de las tablas de ordenación lingüística. Por lo tanto, la asignación es independiente de la configuración regional.

Para obtener más información sobre las secuencias equivalentes canónicamente en Unicode y cadenas canónicamente similares en Unicode, vea Usar la normalización Unicode para representar cadenas.

Ordenar puntos de código

Algunos puntos de código Unicode no tienen peso, por ejemplo, ZERO WIDTH NON JOINER, U+200c. Las funciones de ordenación evalúan intencionadamente los puntos de código sin peso como equivalentes porque no tienen peso en la ordenación. En Windows Vista y versiones posteriores, la aplicación puede ordenar estos puntos de código llamando a las funciones de comparación de cadenas NLS, especialmente CompareStringOrdinal, para la evaluación de todos los puntos de código en un sentido literal, binario, por ejemplo, en la validación de contraseñas. En los sistemas operativos anteriores a Windows Vista, la aplicación debe usar la función en tiempo de ejecución de C strcmp o wcscmp.

Las funciones de ordenación omiten diacríticos, como NON SPACING BREVE, U+0306, cuando la aplicación especifica la marca de hlink_NONSPACE. De forma similar, estas funciones omiten símbolos, por ejemplo, EQUALS SIGN, U+003d , cuando se especifica la marca hlink_SYMBOLS. En Windows Vista y versiones posteriores, la aplicación llama a CompareStringOrdinal para la evaluación de diacríticos y puntos de código de símbolos en un sentido literal y binario. En los sistemas operativos anteriores a Windows Vista, la aplicación debe usar strcmp o wcscmp.

Algunos puntos de código, como 0xFFFF y 0x058b, no están asignados actualmente en Unicode. Estos puntos de código no reciben ningún peso en la ordenación y nunca deben pasarse a las funciones de ordenación. La aplicación debe usar IsNLSDefinedString para detectar puntos de código no Unicode en un flujo de datos.

Nota

Los resultados de IsNLSDefinedString pueden variar en función de la versión Unicode pasada si se agrega un carácter a Unicode en una versión posterior y posteriormente se agrega a las tablas de ordenación de Windows. Para obtener más información, vea Usar control de versiones de ordenación.

 

Ordenar dígitos como números

En Windows 7 y versiones posteriores, la aplicación puede llamar a CompareString, CompareStringEx, LCMapString o LCMapStringEx mediante la marca SORT_DIGITSASNUMBERS. Esta marca admite la ordenación que trata los dígitos como números, por ejemplo, la ordenación de "2" antes de "10".

Tenga en cuenta que el uso de esta marca no es adecuado para dígitos hexadecimales, como los siguientes.

01AF
1BCD
002A
12FA
AB1C
AB02
AB12

En este caso, los "números" se ordenan en orden, pero el usuario percibe una lista hexadecimal mal ordenada.

Asignar cadenas

La aplicación usa la función LCMapString o LCMapStringEx para asignar cadenas, si no se especifica LCMAP_SORTKEY. Una cadena asignada termina en null si la cadena de origen está terminada en null.

Al transformar entre mayúsculas y minúsculas, la función no garantiza que un solo carácter se asigne a un solo carácter. Por ejemplo, los LCMAP_LOWERCASE y las marcas de LCMAP_UPPERCASE pueden asignarse a sí mismo las marcas alemanas Sharp S ("ß"). Como alternativa, la marca de LCMAP_UPPERCASE puede asignar "ß" a "SS" y la marca LCMAP_LOWERCASE puede asignar "SS" a "ß". El comportamiento depende de la versión nlS.

Al transformar entre mayúsculas y minúsculas, la función no distingue el contexto. Por ejemplo, mientras que la marca LCMAP_UPPERCASE asigna correctamente la sigma minúscula griega ("σ") y el sigma final griego en minúsculas ("Σ") a sigma mayúscula griega ("Σ"), la marca LCMAP_LOWERCASE siempre asigna "Σ" a "σ", nunca a "Σ".

De forma predeterminada, la función asigna la "i" minúscula a la "I" mayúscula, incluso cuando el parámetro Locale especifica Turco o Azerbaiyano. Para invalidar este comportamiento para turco o azerbaiyano, la aplicación debe especificar LCMAP_LINGUISTIC_CASING. Si se especifica esta marca con la configuración regional adecuada, "ı" (I sin puntos en minúscula) es la forma minúscula de "I" (I sin puntos mayúsculas) y "i" (punto en minúscula I) es la forma minúscula de "İ" (punto en mayúscula I).

Si se especifica la marca LCMAP_HIRAGANA para asignar caracteres katakana a caracteres hiragana y no se especifica LCMAP_FULLWIDTH, LCMapString o LCMapStringEx solo asigna caracteres de ancho completo a hiragana. En este caso, los caracteres katakana de ancho medio se colocan como en la cadena de destino, sin ninguna asignación a hiragana. La aplicación debe especificar LCMAP_FULLWIDTH para asignar caracteres katakana de ancho medio a hiragana. La razón de esta restricción es que todos los caracteres hiragana son caracteres de ancho completo.

Si la aplicación necesita quitar caracteres de la cadena de origen, puede llamar a la función de asignación con las marcas NORM_IGNORESYMBOLS y NORM_IGNORENONSPACE establecidas y todas las demás marcas desactivadas. Si la aplicación lo hace con una cadena de origen que no está terminada en null, es posible que la función devuelva una cadena vacía y no devuelva un error.

Crear claves de ordenación

Cuando la aplicación especifica LCMAP_SORTKEY, LCMapString o LCMapStringEx genera una clave de ordenación, una matriz binaria de valores de bytes. La clave de ordenación no es una cadena verdadera y sus valores representan el comportamiento de ordenación de la cadena de origen, pero no son valores de visualización significativos.

Nota

La función omite el kashida árabe durante la generación de una clave de ordenación. Si una aplicación llama a la función para crear una clave de ordenación para una cadena que contiene un kashida árabe, la función no crea ningún valor de clave de ordenación.

 

La clave de ordenación puede contener un número impar de bytes. La marca LCMAP_BYTEREV solo invierte un número par de bytes. El último byte (en posición impar) de la clave de ordenación no se invierte. Si el byte de terminación 0x00 es un byte con posición impar, permanece el último byte en la clave de ordenación. Si el byte de terminación 0x00 es un byte de posición uniforme, intercambia posiciones con el byte que lo precede.

Al generar la clave de ordenación, la función trata el guión y el apóstrofo de forma diferente de otros símbolos de puntuación, de modo que las palabras como "coop" y "co-op" permanezcan juntas en una lista. Todos los símbolos de puntuación distintos del guión y el apóstrofo ordenan antes que los caracteres alfanuméricos. La aplicación puede cambiar este comportamiento estableciendo la marca SORT_STRINGSORT, como se describe en Ordenar funciones.

Cuando se usa en memcmp, la clave de ordenación genera el mismo orden que cuando se usa la cadena de origen en CompareString o CompareStringEx. La función memcmp debe usarse en lugar de strcmp, ya que la clave de ordenación puede tener bytes NULL incrustados.

Usar control de versiones de ordenación

Una tabla de ordenación tiene dos números que identifican su versión: la versión definida y la versión NLS. Ambos números son valores DWORD, compuestos de un valor principal y un valor secundario. El primer byte de un valor está reservado, los dos bytes siguientes representan la versión principal y el último byte representa la versión secundaria. En términos hexadecimales, el patrón es 0xRRMMMMmm, donde R es igual a Reservado, M es igual a mayor y m es menor. Por ejemplo, una versión principal de 3 con una versión secundaria de 4 se representa como 0x304.

La versión definida identifica el repertorio de puntos de código y es el mismo para todas las configuraciones regionales. La versión principal se incrementa para indicar los cambios en los puntos de código existentes. La versión secundaria aumenta para indicar que se han agregado puntos de código, pero que no se han cambiado puntos de código existentes anteriormente.

La versión nlS es específica de un identificador de configuración regional o un nombre de configuración regional, y realiza un seguimiento de los cambios en los pesos de punto de código para la configuración regional afectada. La versión principal aumenta cuando se cambian los pesos para los puntos de código que ya se pueden ordenar. La versión secundaria aumenta cuando se asignan pesos de nuevos puntos de código, pero todos los demás pesos de punto de código que se pueden ordenar previamente permanecen sin cambios.

Nota

Para una versión principal, se cambian uno o varios puntos de código para que la aplicación deba volver a indexar todos los datos para que las comparaciones sean válidas. Para una versión secundaria, no se mueve nada, pero se agregan puntos de código. Para este tipo de versión, la aplicación solo tiene que volver a indexar cadenas con valores no ordenados anteriormente.

 

Importante

La versión principal se ha cambiado en Windows 8. Los datos creados en versiones anteriores de Windows deben volver a indexarse.

 

Tanto las versiones definidas como NLS se aplican a los puntos de código ordenables recuperados mediante la función LCMapString o LCMapStringEx con la marca de LCMAP_SORTKEY y también se usan en las funciones CompareString, CompareStringEx, FindNLSString y FindNLSStringEx. Si uno o varios puntos de código de una cadena no se pueden ordenar, la función IsNLSDefinedString devuelve FALSE cuando esa cadena se pasa a ella como parámetro.

La aplicación puede llamar a GetNLSVersion o GetNLSVersionEx para recuperar la versión definida y la versión NLS para una tabla de ordenación.

Indexación de la base de datos

Por motivos de rendimiento, la aplicación debe seguir este procedimiento al indexar la base de datos.

Para indexar correctamente la base de datos

  1. Para cada función, almacene la versión NLS, las claves de ordenación de esa versión y una indicación de ordenación para cada cadena indizada.
  2. Cuando se incrementa la versión secundaria, vuelva a indexar cadenas que antes no se pueden clasificar. Las cadenas afectadas en esta actualización se deben limitar a las para las que IsNLSDefinedString ha devuelto previamente FALSE.
  3. Cuando se incrementa la versión principal, vuelva a indexar todas las cadenas porque los pesos actualizados podrían cambiar el comportamiento de cualquier cadena. Las versiones principales son muy poco frecuentes.

Los problemas de indexación de base de datos pueden surgir por los siguientes motivos:

  • Un sistema operativo posterior puede definir puntos de código que no están definidos para un sistema operativo anterior, cambiando así la ordenación.
  • Los puntos de código pueden tener diferentes pesos de ordenación en diferentes sistemas operativos, debido a correcciones en la compatibilidad con idiomas.

Para minimizar la necesidad de volver a indexar la base de datos en estas circunstancias, la aplicación puede usar IsNLSDefinedString para diferenciar definida de cadenas no definidas para que la aplicación pueda rechazar cadenas con puntos de código no definidos. El uso de GetNLSVersion o GetNLSVersionEx permite a la aplicación determinar si un cambio NLS afecta a la configuración regional usada para una tabla de índice determinada. Si el cambio no tiene ningún efecto en la configuración regional, la aplicación no necesita volver a indexar la tabla.

Ejemplos

En la tabla siguiente se muestran los efectos de determinadas marcas usadas con las funciones de ordenación. En cada caso, la selección de marcas determina si dos caracteres diferentes se consideran iguales con fines de ordenación.

Carácter 1 Carácter 2 Default NORM_IGNOREWIDTH NORM_IGNOREKANA NORM_IGNOREWIDTH| NORMIGNOREKANA
"あ"
U+3042 HIRAGANA LETTER A
"ガ"
U+30A2 KATAKANA LETTER A
Desigual Desigual Igual Igual
"オ"
U+FF75 HALFWIDTH KATAKANA LETTER O
"オ"
U+30AA KATAKANA LETTER O
Desigual Igual Desigual Igual
"B"
U+FF22 FULLWIDTH LETRA MAYÚSCULA LATINA B
"B"
U+0042 LETRA MAYÚSCULA LATINA B
Desigual Igual Desigual Igual

 

Uso de la compatibilidad con idiomas nacionales

Ordenar

Recuperar y establecer información de configuración regional

Uso de la normalización Unicode para representar cadenas

Consideraciones de seguridad: Características internacionales

CompareString

CompareStringEx

CompareStringOrdinal

FindNLSString

FindNLSStringEx

LCMapString

LCMapStringEx