2010-08-13 12 views
8

He encontrado esto en el artículo de Wikipedia sobre UTF-8:¿Comparar cadenas de dos bytes [] de utf-8 es lo mismo que comparar dos cadenas de unicode?

Clasificación de cadenas UTF-8 como matrices de bytes sin signo producirán los mismos resultados que clasificarlos en base a los puntos de código Unicode.

que me llevaría a creer que para fines de comparación (clasificación, búsqueda binaria, etc.) que la comparación de dos matrices de bytes (es decir, el byte a byte como memcmp) de cadenas UTF-8 codificados daría los mismos resultados como la comparación de las cadenas de Unicode reales.

¿Es esto cierto?

Respuesta

5

Depende de lo que quiere decir con "comparar las cadenas de Unicode reales".

Si solo va a comparar los puntos de código (como números de 32 bits) en lugar de los puntos de código codificados UTF-8, entonces la respuesta es sí: eso dará los mismos resultados. La asignación de puntos de código a bytes codificados en UTF-8 es uno a uno.

Si va a hacer una comparación de cadenas Unicode adecuada, en lugar de una comparación byte del UTF-8, la respuesta es no. En Unicode, puede haber diferentes formas de representar el mismo personaje. Por ejemplo, E puede ser representado en (al menos) dos maneras:

  • U+00e9 (LATIN SMALL LETTER E WITH ACUTE), o
  • U+0065 (LATIN SMALL LETTER E) seguido de U+0301 (COMBINING ACUTE ACCENT).

Una función de comparación Unicode correctamente escrita considerará que estos dos son idénticos.

+0

Como Jon Hanna señala en su respuesta, en .NET se comparan los puntos de código como pares sustituyentes UTF-16, no números de 32 bits, por lo que en realidad se obtienen resultados diferentes. Pero acepté su respuesta porque usted fue el primero en señalar que la comparación significativa de cadenas Unicode no debe basarse en los puntos de código. – Eloff

+0

No llamaría a esto una comparación de cadenas Unicode "adecuada", sino una comparación de cadenas "lingüísticas".Hay muchos usos de la comparación de cadenas que no son lingüísticos, como la implementación de tipos de datos de almacenamiento y recuperación y algoritmos como 'quicksort',' binary search', etc. En tales casos, usted quiere el pedido confiable más rápido. – hippietrail

+0

No estoy de acuerdo con @hippietrail, ya que en todos los casos que se mencionan, uno querría que U + 00e9 fuera lo mismo que U + 0065 seguido de U + 0301. ¿Existe una comparación de cadenas Unicode "adecuada"? – vy32

3

No, no lo es.

Por ejemplo, se puede escribir como un único punto de código (U+00C0 CAPITAL AMÉRICA CARTA A con grave) o como dos puntos de código (U+0041 Letra latina mayúscula A U+0300 COMBINACIÓN acento grave).

Ambas representaciones deben ser iguales, pero tendrán diferentes codificaciones de bytes.

+0

Seguramente estos dos puntos de codificación codificarían para diferentes secuencias de bytes UTF-8? ¿O está diciendo que no puede hacer un viaje de ida y vuelta a Unicode -> UTF-8 -> Unicode? –

+0

No, está diciendo que una cadena en Unicode NFC y la misma cadena en NFD (para llevar ejemplos de posibles estados de normalización) y la misma cadena que no está normalizada no tendrá la misma secuencia de puntos de código. Además, no tiene sentido hablar de un disparo de ida y vuelta entre UTF-8 y Unicode, ya que UTF-8 * es * Unicode, simplemente almacenado en un orden particular de bytes. –

+0

¿Conoces una función de comparación Unicode que realmente se comporte de esta manera? – vy32

5

Sí, dado que hay un mapeo uno a uno entre bytes de secuencias en codificación UTF-8 y puntos de código Unicode.

Sin embargo, hay forma de comparar cadenas Unicode además de ver los puntos de código sin formato. Si solo mira los puntos de código - o los bytes UTF-8 - como números, entonces omite la lógica de comparación específica de la cultura.

Para implementar la comparación y la clasificación correctamente para una cultura específica, en .NET, debe utilizar las funciones de comparación de cadenas estándar.

0

He encontrado esto en el artículo de Wikipedia sobre UTF-8:

Clasificación de cadenas UTF-8 como matrices de bytes sin signo producirán los mismos resultados que clasificarlos en base a los puntos de código Unicode.

que me llevaría a creer que para fines de comparación (clasificación, búsqueda binaria, etc.) que la comparación de dos matrices de bytes (es decir, el byte a byte como memcmp) de cadenas UTF-8 codificados daría los mismos resultados como la comparación de las cadenas de Unicode reales.

Todo esto depende de lo que quiere decir con "cadenas de Unicode reales" y qué quiere decir con "comparar". En .Net Framework, las cadenas se encuentran en la forma UTF-16 de Unicode. Una comparación binaria simple entre cadenas UTF-16 generará un orden de clasificación diferente a la misma comparación entre las cadenas UTF-8 y UTF-32 (la versión del punto de código al que se hace referencia en la cita).

Pero una comparación binaria de cualquiera de esas cosas no es muy útil. Debería utilizar las comparaciones integradas de cultivo integradas. Esto es porque dos cadenas que son, para todos los efectos, las mismas se pueden construir a partir de diferentes secuencias de puntos de código. Las comparaciones integradas toman esas cosas en cuenta.

5

Es lo mismo que un punto de código para la comparación de punto de código, es decir, uno que no presta atención al plegado de mayúsculas, ordenamientos culturales, composición o cualquier otra cosa que no sea el valor Unicode.

Esto es bastante inútil cuando se consideran las cadenas como un trozo de texto legible por humanos, pero a veces lo que desea es ser capaz de poner las cadenas en un ordenamiento, ya que algunos algoritmos (búsqueda binaria como usted dice) necesitará una ordenamiento consistente, pero los detalles de ese ordenamiento consistente no son significativos.

Sin embargo, es importante tener en cuenta que la comparación ordinal en cadenas ofrecida por .NET funciona en el UTF-16 utilizado internamente que no contiene mantener el orden del punto de código. Si comparamos una cadena con solo el carácter U + FF61 y una cadena con solo el carácter U + 10002, entonces .NET almacenará este último como pares de sustitución, de 0xD800 y 0XDC02.

Por lo tanto:

string.CompareOrdinal("\U0000ff61", "\U00010002"); 

y

string.Compare("\U0000ff61", "\U00010002", StringComparison.Ordinal); 

ambos valores de retorno grandes que cero, a pesar de que el primero es más baja en valor de código de punto que el último (I utiliza la forma \ U en vez que el \ u forma para aclarar eso).

Si por "las cadenas de Unicode reales" quiere decir las cadenas .NET UTF-16, entonces la respuesta a su pregunta es no, por la razón opuesta a la que lo llevó a pensar que podría funcionar.

+0

Fascinante, obtendría un pedido con UTF-8, y sería un pedido de punto de código, a diferencia de lo que produce la comparación ordinal invariante de cultura en .NET, simplemente porque .NET usa UTF-16 que no da código. ordenamiento de puntos Eso es sutil y seguro convertir algún programador pobre prematuramente gris: P – Eloff

+1

Tenga en cuenta también que invariante de cultura es diferente a ordinal. La cultura invariante es más o menos una cultura inventada (que se parece más a la cultura angloamericana del "medio Atlántico" compartida entre EE. UU. Y la Commonwealth que cualquier otra cultura) que es útil cuando se necesita forzar un comportamiento consistente sobre culturalmente correcto manejo. Las comparaciones ordinales son * estrictamente * para cuando necesita un orden arbitrario (es culturalmente basura pero es rápido) o para ingenuamente comparar cadenas para que coincida con un estándar (por ejemplo, código de computadora de análisis). –

+1

Tal vez podríamos llamar ordinal, "culturalmente ignorante" :) –

Cuestiones relacionadas