c# .net unicode unicode-escapes

c# - Convertir Unicode par suplente a cadena literal



.net unicode-escapes (2)

Estoy tratando de leer un alto carácter Unicode de una cadena a otra. Para abreviar, simplificaré mi código como se muestra a continuación:

public static void UnicodeTest() { var highUnicodeChar = "𝐀"; //Not the standard A var result1 = highUnicodeChar; //this works var result2 = highUnicodeChar[0].ToString(); // returns /ud835 }

Cuando asigno highUnicodeChar a result1 directamente, conserva su valor literal de 𝐀 . Cuando intento acceder a él por índice, devuelve /ud835 . Como lo entiendo, este es un par suplente de caracteres UTF-16 utilizados para representar un carácter UTF-32. Estoy bastante seguro de que este problema tiene que ver con tratar de convertir implícitamente un char en una string .

Al final, quiero que result2 produzca el mismo valor que result1 . ¿Cómo puedo hacer esto?


En Unicode, tienes puntos de código . Estos son 21 bits de largo. Su carácter 𝐀, "Matemáticas negrita mayúscula A", tiene un punto de código de U + 1D400.

En las codificaciones Unicode, tienes unidades de código . Estas son las unidades naturales de la codificación: 8 bits para UTF-8, 16 bits para UTF-16, etc. Una o más unidades de código codifican un solo punto de código.

En UTF-16, dos unidades de código que forman un solo punto de código se denominan un par sustituto . Los pares sustitutos se utilizan para codificar cualquier punto de código superior a 16 bits, es decir, U + 10000 y superiores.

Esto se vuelve un poco complicado en .NET, ya que una .NET Char representa una única unidad de código UTF-16, y una .NET String es una colección de unidades de código.

Por lo tanto, su punto de código 𝐀 (U + 1D400) no puede caber en 16 bits y necesita un par suplente, lo que significa que su cadena tiene dos unidades de código:

var highUnicodeChar = "𝐀"; char a = highUnicodeChar[0]; // code unit 0xD835 char b = highUnicodeChar[1]; // code unit 0xDC00

Es decir, cuando indexas en la cadena de esa manera, en realidad solo obtienes la mitad del par suplente.

Puede usar IsSurrogatePair para probar un par suplente. Por ejemplo:

string GetFullCodePointAtIndex(string s, int idx) => s.Substring(idx, char.IsSurrogatePair(s, idx) ? 2 : 1);

Es importante tener en cuenta que el agujero de conejo de la codificación variable en Unicode no termina en el punto de código. Un grupo de grafemas es la "cosa visible" que la mayoría de las personas, cuando se les pregunta, en última instancia, llaman un "carácter". Un grupo de grafemas se crea a partir de uno o más puntos de código: un carácter base y cero o más caracteres combinados. Un ejemplo de un carácter de combinación es una diéresis u otras decoraciones / modificadores que desee agregar. Vea esta respuesta para ver un ejemplo horrible de lo que pueden hacer los personajes combinados.

Para probar un carácter de combinación, puede usar GetUnicodeCategory para verificar si hay una marca de GetUnicodeCategory una marca sin espacio o una marca de espacio.


Parece que desea extraer el primer carácter "atómico" desde el punto de vista del usuario (es decir, el primer grupo de grafemas Unicode) de la cadena highUnicodeChar , donde un carácter "atómico" incluye las dos mitades de un par suplente .

Puede usar StringInfo.GetTextElementEnumerator() para hacer precisamente esto, dividir una string en trozos atómicos y luego tomar la primera.

Primero, define el siguiente método de extensión:

public static class TextExtensions { public static IEnumerable<string> TextElements(this string s) { // StringInfo.GetTextElementEnumerator is a .Net 1.1 class that doesn''t implement IEnumerable<string>, so convert if (s == null) yield break; var enumerator = StringInfo.GetTextElementEnumerator(s); while (enumerator.MoveNext()) yield return enumerator.GetTextElement(); } }

Ahora, puedes hacer:

var result2 = highUnicodeChar.TextElements().FirstOrDefault() ?? "";

Tenga en cuenta que StringInfo.GetTextElementEnumerator() también StringInfo.GetTextElementEnumerator() caracteres de combinación de Unicode, de modo que el primer grupo de grafemas de la cadena HĖ‚=TĖ‚+VĖ‚ será HĖ‚ no H

Muestra de violín here .