El proyecto ICU (que ahora también tiene una biblioteca PHP ) contiene las clases necesarias para ayudar a normalizar las cadenas UTF-8 para facilitar la comparación de valores al buscar.
Sin embargo, estoy tratando de averiguar qué significa esto para las aplicaciones. Por ejemplo, ¿en qué casos quiero "Equivalencia canónica" en lugar de "Equivalencia de compatibilidad", o viceversa?
php
c
unicode
unicode-normalization
Xeoncross
fuente
fuente
(begin curved line) (char1) (char2) … (charN) (end curved line)
en lugar de esto:(curved line marker prefix) (char1) (curved line marker prefix) (char2) (curved line marker prefix) (char2)
. En otras palabras, ¿unidad mínima que se puede representar?Respuestas:
Todo lo que nunca quiso saber sobre la normalización Unicode
Normalización canónica
Unicode incluye múltiples formas de codificar algunos caracteres, especialmente los caracteres acentuados. La normalización canónica cambia los puntos de código en una forma de codificación canónica. Los puntos de código resultantes deben aparecer idénticos a los originales, salvo los errores en las fuentes o el motor de representación.
Cuándo usar
Debido a que los resultados parecen idénticos, siempre es seguro aplicar la normalización canónica a una cadena antes de almacenarla o mostrarla, siempre que pueda tolerar que el resultado no sea bit por bit idéntico a la entrada.
La normalización canónica viene en 2 formas: NFD y NFC. Los dos son equivalentes en el sentido de que uno puede convertir entre estas dos formas sin pérdida. Comparar dos cadenas bajo NFC siempre dará el mismo resultado que compararlas bajo NFD.
NFD
NFD tiene los personajes completamente expandidos. Esta es la forma de normalización más rápida de calcular, pero da como resultado más puntos de código (es decir, usa más espacio).
Si solo desea comparar dos cadenas que aún no están normalizadas, esta es la forma de normalización preferida a menos que sepa que necesita normalización de compatibilidad.
NFC
NFC recombina puntos de código cuando es posible después de ejecutar el algoritmo NFD. Esto lleva un poco más de tiempo, pero da como resultado cadenas más cortas.
Normalización de compatibilidad
Unicode también incluye muchos caracteres que realmente no pertenecen, pero se usaron en conjuntos de caracteres heredados. Unicode agregó estos para permitir que el texto en esos juegos de caracteres se procese como Unicode y luego se convierta de nuevo sin pérdida.
La normalización de compatibilidad los convierte en la secuencia correspondiente de caracteres "reales", y también realiza la normalización canónica. Los resultados de la normalización de compatibilidad pueden no parecer idénticos a los originales.
Los caracteres que incluyen información de formato se reemplazan por otros que no. Por ejemplo, el personaje
⁹
se convierte a9
. Otros no implican diferencias de formato. Por ejemplo, el carácter del número romanoⅨ
se convierte en las letras regularesIX
.Obviamente, una vez que se ha realizado esta transformación, ya no es posible volver a convertir sin pérdidas al conjunto de caracteres original.
Cuándo usar
El Consorcio Unicode sugiere pensar en la normalización de compatibilidad como una
ToUpperCase
transformación. Es algo que puede ser útil en algunas circunstancias, pero no solo debe aplicarlo de todas formas.Un excelente caso de uso sería un motor de búsqueda, ya que probablemente desee una búsqueda
9
que coincida⁹
.Una cosa que probablemente no debería hacer es mostrar el resultado de aplicar la normalización de compatibilidad al usuario.
NFKC / NFKD
La forma de normalización de compatibilidad viene en dos formas NFKD y NFKC. Tienen la misma relación que entre NFD y C.
Cualquier cadena en NFKC es inherentemente también en NFC, y lo mismo para NFKD y NFD. Por lo tanto
NFKD(x)=NFD(NFKC(x))
, yNFKC(x)=NFC(NFKD(x))
, etc.Conclusión
En caso de duda, vaya con la normalización canónica. Elija NFC o NFD según la compensación de espacio / velocidad aplicable, o según lo que requiera algo con lo que está interactuando.
fuente
NFC(x)=Recompose(NFD(x))
.Algunos caracteres, por ejemplo, una letra con acento (por ejemplo,
é
) se pueden representar de dos maneras: un solo punto de códigoU+00E9
o la letra simple seguida de una marca de acento combinadaU+0065 U+0301
. La normalización ordinaria elegirá uno de estos para representarlo siempre (el punto de código único para NFC, la forma de combinación para NFD).Para los caracteres que podrían representarse mediante múltiples secuencias de caracteres base y marcas combinadas (por ejemplo, "s, punto debajo, punto arriba" frente a poner punto arriba y luego punto abajo o usar un carácter base que ya tiene uno de los puntos), NFD también elija uno de estos (a continuación va primero, como sucede)
Las descomposiciones de compatibilidad incluyen una serie de caracteres que "realmente no deberían ser", pero se deben a que se usaron en codificaciones heredadas. La normalización ordinaria no los unificará (para preservar la integridad del viaje de ida y vuelta; esto no es un problema para las formas combinadas porque no se utilizó codificación heredada [excepto un puñado de codificaciones vietnamitas]), pero la normalización de compatibilidad sí lo hará. Piense como el signo de kilogramo "kg" que aparece en algunas codificaciones de Asia oriental (o el katakana de medio ancho / ancho completo y el alfabeto), o la ligadura "fi" en MacRoman.
Ver http://unicode.org/reports/tr15/ para más detalles.
fuente
Las formas normales (de Unicode, no de bases de datos) tratan principalmente (¿exclusivamente?) Con caracteres que tienen signos diacríticos. Unicode proporciona algunos caracteres con signos diacríticos "incorporados", como U + 00C0, "Latin A mayúscula con tumba". Se puede crear el mismo carácter a partir de una `A mayúscula latina" (U + 0041) con un "Acento grave combinado" (U + 0300). Eso significa que, aunque las dos secuencias producen el mismo carácter resultante, un byte por byte la comparación los mostrará como completamente diferentes.
La normalización es un intento de lidiar con eso. La normalización asegura (o al menos lo intenta) que todos los caracteres están codificados de la misma manera, ya sea utilizando una marca diacrítica de combinación separada donde sea necesario, o todos utilizando un único punto de código siempre que sea posible. Desde el punto de vista de la comparación, en realidad no importa mucho lo que elija: prácticamente cualquier cadena normalizada se comparará correctamente con otra cadena normalizada.
En este caso, "compatibilidad" significa compatibilidad con el código que supone que un punto de código equivale a un carácter. Si tiene un código como ese, probablemente quiera usar la forma normal de compatibilidad. Aunque nunca lo he visto expresado directamente, los nombres de las formas normales implican que el consorcio Unicode considera preferible usar marcas diacríticas combinadas por separado. Esto requiere más inteligencia para contar los caracteres reales en una cadena (así como cosas como romper una cadena de manera inteligente), pero es más versátil.
Si está haciendo un uso completo de la UCI, es probable que desee usar la forma canónica normal. Si está intentando escribir código por su cuenta que (por ejemplo) asume que un punto de código es igual a un carácter, entonces probablemente desee la forma normal de compatibilidad que hace que eso sea cierto con la mayor frecuencia posible.
fuente
"o\x{332}\x{303}\x{304}"
, y NFC es"\x{22D}\x{332}"
. Para el segundo NFD es"o\x{332}\x{304}\x{303}"
y NFC es"\x{14D}\x{332}\x{303}"
. Sin embargo, existen muchas posibilidades no canónicas que son canónicamente equivalentes a estas. La normalización permite la comparación binaria de grafemas canónicamente equivalentes.Si dos cadenas unicode son canónicamente equivalentes, las cadenas son realmente iguales, solo que usan diferentes secuencias unicode. Por ejemplo, Ä puede representarse utilizando el carácter Ä o una combinación de A y ◌̈.
Si las cadenas son solo equivalentes de compatibilidad, las cadenas no son necesariamente las mismas, pero pueden ser iguales en algunos contextos. Por ejemplo, ff podría considerarse igual que ff.
Entonces, si está comparando cadenas, debe usar equivalencia canónica, porque la equivalencia de compatibilidad no es equivalencia real.
Pero si desea ordenar un conjunto de cadenas, podría tener sentido utilizar la equivalencia de compatibilidad, ya que son casi idénticas.
fuente
Esto es realmente bastante simple. UTF-8 en realidad tiene varias representaciones diferentes del mismo "personaje". (Uso el carácter entre comillas, ya que los bytes son diferentes, pero prácticamente son lo mismo). Se da un ejemplo en el documento vinculado.
El carácter "Ç" se puede representar como la secuencia de bytes 0xc387. Pero también se puede representar con un
C
(0x43) seguido de la secuencia de bytes 0xcca7. Entonces puedes decir que 0xc387 y 0x43cca7 son el mismo personaje. La razón que funciona es que 0xcca7 es una marca de combinación; es decir, toma el carácter antes que él (aC
aquí) y lo modifica.Ahora, en lo que respecta a la diferencia entre equivalencia canónica versus equivalencia de compatibilidad, necesitamos observar los caracteres en general.
Hay 2 tipos de caracteres, los que transmiten significado a través del valor y los que toman otro carácter y lo alteran. 9 es un personaje significativo. Un súper script ⁹ toma ese significado y lo altera por presentación. Así que canónicamente tienen diferentes significados, pero aún representan el carácter base.
La equivalencia canónica es donde la secuencia de bytes representa el mismo carácter con el mismo significado. La equivalencia de compatibilidad es cuando la secuencia de bytes está representando un carácter diferente con el mismo significado base (aunque pueda estar alterado). El 9 y ⁹ son equivalentes de compatibilidad ya que ambos significan "9", pero no son canónicamente equivalentes ya que no tienen la misma representación.
fuente
Si la equivalencia canónica o la equivalencia de compatibilidad es más relevante para usted depende de su aplicación. La forma de pensar ASCII sobre las comparaciones de cadenas se correlaciona aproximadamente con la equivalencia canónica, pero Unicode representa muchos idiomas. No creo que sea seguro suponer que Unicode codifica todos los idiomas de una manera que le permite tratarlos como ASCII de Europa occidental.
Las Figuras 1 y 2 proporcionan buenos ejemplos de los dos tipos de equivalencia. Bajo equivalencia de compatibilidad, parece que el mismo número en forma de sub y scripts se compararía igual. Pero no estoy seguro de que resuelva el mismo problema que la forma árabe cursiva o los caracteres rotados.
La dura realidad del procesamiento de texto Unicode es que tiene que pensar profundamente sobre los requisitos de procesamiento de texto de su aplicación y luego abordarlos lo mejor que pueda con las herramientas disponibles. Eso no responde directamente a su pregunta, pero una respuesta más detallada requeriría expertos lingüísticos para cada uno de los idiomas que espera admitir.
fuente
El problema de comparar cadenas : dos cadenas con contenido equivalente para la mayoría de las aplicaciones pueden contener secuencias de caracteres diferentes.
Consulte la equivalencia canónica de Unicode : si el algoritmo de comparación es simple (o debe ser rápido), la equivalencia de Unicode no se realiza. Este problema ocurre, por ejemplo, en la comparación canónica XML, consulte http://www.w3.org/TR/xml-c14n
Para evitar este problema ... ¿Qué estándar usar? ¿"UTF8 expandido" o "UTF8 compacto"?
Utilice "ç" o "c + ◌̧".
W3C y otros (por ejemplo , nombres de archivo ) sugieren utilizar el "compuesto como canónico" (tenga en cuenta C de las cadenas más cortas "más compactas") ... Entonces,
El estándar es C ! en duda use NFC
Para la interoperabilidad, y para las opciones de "convención sobre configuración" , la recomendación es el uso de NFC , para "canonizar" cadenas externas. Para almacenar XML canónico, por ejemplo, guárdelo en "FORM_C". El Grupo de Trabajo CSV en la Web del W3C también recomienda NFC (sección 7.2).
PS: de "FORM_C" es el formulario predeterminado en la mayoría de las bibliotecas. Ex. en PHP normalizer.isnormalized () .
El término " forma de composición " (
FORM_C
) se usa para ambos, para decir que "una cadena está en la forma C-canónica" (el resultado de una transformación NFC) y para decir que se usa un algoritmo de transformación ... Ver http: //www.macchiato.com/unicode/nfc-faqNota: para probar la normalización de cadenas pequeñas (referencias UTF-8 puras o entidades XML), puede usar este convertidor en línea de prueba / normalización .
fuente