c# unicode rtf codepoint

Cómo enviar una cadena Unicode a RTF(usando C#)



codepoint (4)

Estoy tratando de dar salida a la cadena Unicode en formato RTF. (usando c # y winforms)

De wikipedia :

Si se requiere un escape de Unicode, se usa la palabra de control / u, seguida de un entero decimal con signo de 16 bits que proporciona el número de punto de código de Unicode. Para el beneficio de los programas sin soporte de Unicode, esto debe ser seguido por la representación más cercana de este carácter en la página de códigos especificada. Por ejemplo, / u1576? daría la letra árabe beh, especificando que los programas más antiguos que no tienen compatibilidad con Unicode deberían presentarla como un signo de interrogación.

No sé cómo convertir un carácter Unicode en un punto de código Unicode ("/ u1576"). La conversión a UTF 8, UTF 16 y similares es fácil, pero no sé cómo convertir a punto de código.

Escenario en el que uso esto:

  • Leí un archivo RTF existente en una cadena (estoy leyendo una plantilla)
  • string.replace # TOKEN # con MyUnicodeString (la plantilla se llena con datos)
  • escriba el resultado en otro archivo RTF.

Problema, surge cuando llegan los personajes Unicode.


De acuerdo con la especificación, aquí hay un código en java que se prueba y funciona:

public static String escape(String s){ if (s == null) return s; int len = s.length(); StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++){ char c = s.charAt(i); if (c >= 0x20 && c < 0x80){ if (c == ''//' || c == ''{'' || c == ''}''){ sb.append(''//'); } sb.append(c); } else if (c < 0x20 || (c >= 0x80 && c <= 0xFF)){ sb.append("/'"); sb.append(Integer.toHexString(c)); }else{ sb.append("//u"); sb.append((short)c); sb.append("??");//two bytes ignored } } return sb.toString(); }

Lo importante es que debe agregar 2 caracteres (cerca del carácter Unicode o simplemente usar? En su lugar) después del Uncode escapado. Porque los Unicode ocupan 2 bytes.

También la especificación dice que debe usar un valor negativo si el código es mayor que 32767, pero en mi prueba, está bien si no usa un valor negativo.

Aquí está la especificación:

/ uN Esta palabra clave representa un solo carácter Unicode que no tiene una representación ANSI equivalente basada en la página de códigos ANSI actual. N representa el valor del carácter Unicode expresado como un número decimal. Esta palabra clave es seguida inmediatamente por caracteres equivalentes en la representación ANSI. De esta manera, los lectores antiguos ignorarán la palabra clave / uN y recogerán la representación ANSI correctamente. Cuando se encuentra esta palabra clave, el lector debe ignorar los siguientes N caracteres, donde N corresponde al último valor / ucN encontrado.

Al igual que con todas las palabras clave RTF, puede haber un espacio de terminación de palabra clave (antes de los caracteres ANSI) que no se cuenta en los caracteres que se van a omitir. Si bien es poco probable que esto ocurra (o se recomienda), una palabra clave / bin, su argumento y los datos binarios que siguen se consideran un carácter para omitir. Si se encuentra un carácter delimitador de alcance RTF (es decir, una llave de apertura o de cierre) al escanear datos omitibles, se considera que los datos omitibles se terminan antes del delimitador. Esto hace posible que un lector realice una recuperación de error rudimentaria. Para incluir un delimitador RTF en los datos que se pueden omitir, se debe representar utilizando el símbolo de control apropiado (es decir, con una barra invertida, como un texto sin formato). Cualquier palabra o símbolo de control RTF se considera un solo carácter con el fin de contar los caracteres que se pueden omitir.

Un escritor RTF, cuando encuentra un carácter Unicode sin un carácter ANSI correspondiente, debe mostrar / uN seguido de la mejor representación ANSI que puede administrar. Además, si el carácter Unicode se traduce en un flujo de caracteres ANSI con un recuento de bytes que difiere del Recuento de bytes del carácter Unicode actual, debe emitir la palabra clave / ucN antes de la palabra clave / uN para notificar al lector el cambio.

Las palabras de control RTF generalmente aceptan números de 16 bits firmados como argumentos. Por esta razón, los valores Unicode mayores que 32767 deben expresarse como un número negativo


Se corrigió el código de la respuesta aceptada: se agregó un escape de caracteres especiales, como se describe en este link

static string GetRtfUnicodeEscapedString(string s) { var sb = new StringBuilder(); foreach (var c in s) { if(c == ''//' || c == ''{'' || c == ''}'') sb.Append(@"/" + c); else if (c <= 0x7f) sb.Append(c); else sb.Append("//u" + Convert.ToUInt32(c) + "?"); } return sb.ToString(); }


Siempre y cuando todos los caracteres que está buscando en el plano bilingüe básico (es poco probable que necesite algo más), una simple codificación UTF-16 debería ser suficiente.

Wikipedia:

Todos los puntos de código posibles desde U + 0000 hasta U + 10FFFF, excepto los puntos de código sustitutos U + D800 – U + DFFF (que no son caracteres), se asignan de forma única por UTF-16 independientemente de la asignación de caracteres actual o futura del punto de código o usar.

El siguiente programa de ejemplo ilustra cómo hacer algo en la línea de lo que desea:

static void Main(string[] args) { // ë char[] ca = Encoding.Unicode.GetChars(new byte[] { 0xeb, 0x00 }); var sw = new StreamWriter(@"c:/helloworld.rtf"); sw.WriteLine(@"{/rtf {/fonttbl {/f0 Times New Roman;}} /f0/fs60 H" + GetRtfUnicodeEscapedString(new String(ca)) + @"llo, World! }"); sw.Close(); } static string GetRtfUnicodeEscapedString(string s) { var sb = new StringBuilder(); foreach (var c in s) { if (c <= 0x7f) sb.Append(c); else sb.Append("//u" + Convert.ToUInt32(c) + "?"); } return sb.ToString(); }

El bit importante es el Convert.ToUInt32(c) que esencialmente devuelve el valor del punto de código para el carácter en cuestión. El escape RTF para unicode requiere un valor decimal de unicode. La codificación System.Text.Encoding.Unicode corresponde a UTF-16 según la documentación de MSDN.


Tendrá que convertir la cadena en una matriz de byte[] (utilizando Encoding.Unicode.GetBytes(string) ), luego recorrer esa matriz y anteponer un carácter / u a todos los caracteres Unicode que encuentre. Cuando luego convierte la matriz de nuevo a una cadena, tendría que dejar los caracteres Unicode como números.

Por ejemplo, si su matriz se ve así:

byte[] unicodeData = new byte[] { 0x15, 0x76 };

se convertiría en

// 5c = /, 75 = u byte[] unicodeData = new byte[] { 0x5c, 0x75, 0x15, 0x76 };