De acuerdo, en .Net y C # todas las cadenas están codificadas como UTF-16LE . A string
se almacena como una secuencia de caracteres. Cada uno char
encapsula el almacenamiento de 2 bytes o 16 bits.
Lo que vemos "en papel o pantalla" como una sola letra, carácter, glifo, símbolo o signo de puntuación puede considerarse como un único Elemento de texto. Como se describe en el Anexo Estándar Unicode # 29 SEGMENTACIÓN DE TEXTO DE UNICODE , cada Elemento de Texto está representado por uno o más Puntos de Código. Puede encontrar una lista exhaustiva de códigos aquí .
Cada punto de código debe codificarse en binario para la representación interna de una computadora. Como se indicó, cada uno char
almacena 2 bytes. Los puntos de código en o debajo U+FFFF
se pueden almacenar en un solo char
. Los puntos de código anteriores U+FFFF
se almacenan como un par sustituto, utilizando dos caracteres para representar un único punto de código.
Dado lo que ahora sabemos que podemos deducir, un elemento de texto puede almacenarse como uno char
, como un par sustituto de dos caracteres o, si el elemento de texto está representado por múltiples puntos de código, alguna combinación de caracteres individuales y pares sustitutos. Como si eso no fuera lo suficientemente complicado, algunos Elementos de texto pueden representarse mediante diferentes combinaciones de Puntos de código como se describe en el Anexo estándar Unicode # 15, FORMAS DE NORMALIZACIÓN DE UNICODE .
Interludio
Por lo tanto, las cadenas que se ven iguales cuando se procesan en realidad pueden estar formadas por una combinación diferente de caracteres. Una comparación ordinal (byte por byte) de dos cadenas de este tipo detectaría una diferencia, esto puede ser inesperado o indeseable.
Puede volver a codificar cadenas .Net. para que usen el mismo formulario de normalización. Una vez normalizado, dos cadenas con los mismos elementos de texto se codificarán de la misma manera. Para hacer esto, use la función string.Normalize . Sin embargo, recuerde que algunos elementos de texto diferentes se parecen entre sí. : -s
Entonces, ¿qué significa todo esto en relación con la pregunta? El elemento de texto '𠈓'
está representado por la única extensión de ideogramas unificados Code Point U + 20213 cjk b . Esto significa que no puede codificarse como único char
y debe codificarse como Par sustituto, utilizando dos caracteres. Es por eso que string b
es uno char
más largo que string a
.
Si necesita contar de manera confiable (ver advertencia) el número de elementos de texto en un string
, debe usar la
System.Globalization.StringInfo
clase de esta manera.
using System.Globalization;
string a = "abc";
string b = "A𠈓C";
Console.WriteLine("Length a = {0}", new StringInfo(a).LengthInTextElements);
Console.WriteLine("Length b = {0}", new StringInfo(b).LengthInTextElements);
dando la salida,
"Length a = 3"
"Length b = 3"
como se esperaba.
Consideración
La implementación .Net de la segmentación de texto Unicode en las clases StringInfo
y TextElementEnumerator
debería ser generalmente útil y, en la mayoría de los casos, producirá una respuesta que la persona que llama espera. Sin embargo, como se indica en el Anexo estándar 29 de Unicode, "El objetivo de hacer coincidir las percepciones de los usuarios no siempre se puede cumplir exactamente porque el texto por sí solo no siempre contiene suficiente información para decidir inequívocamente los límites".