2009-09-02 17 views
16

Estoy intentando dar salida a la cadena Unicode en formato RTF. (Utilizando C# y winforms)Cómo dar salida a la cadena Unicode a RTF (usando C#)

From wikipedia:

Si se requiere un escape Unicode, la palabra de control \ u se utiliza, seguido de un 16-bit número entero decimal con signo que indica el número de puntos de código Unicode. Para el beneficio de programas sin soporte Unicode, esto debe ir seguido de 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 arábica beh, especificando que los programas anteriores que no tienen soporte Unicode deberían representarlo como un signo de interrogación.

No sé cómo convertir caracteres Unicode en puntos de código Unicode ("\ u1576"). La conversión a UTF 8, UTF 16 y similar es fácil, pero no sé cómo convertir a punto de código.

escenario en el que yo uso esto:

  • que leer el archivo RTF en cadena (estoy plantilla de lectura)
  • String.Replace # # simbólico con MyUnicodeString existente (plantilla es poblar con datos)
  • escribe el resultado en otro archivo RTF.

problema, surgen cuando los caracteres Unicode llegaron

Respuesta

25

A condición de que todos los personajes que estás catering para existir en el Basic Multilingual Plane (que es poco probable que necesitará algo más), entonces una simple codificación UTF-16 debería ser suficiente.

Wikipedia:

Todos los posibles puntos de código de U + 0000 través U + 10FFFF, a excepción de los puntos de código de sustitución U + D800-U + DFFF (que no son caracteres), son asignada de manera única por UTF-16 independientemente de de la asignación o uso de caracteres actuales o futuros del punto de código .

El siguiente programa de ejemplo ilustra haciendo algo en la línea de lo que quiere:

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(); 
} 

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

+0

hmmmm, punto muy interesante.Si eso es cierto, entonces, probablemente haya un error en alguna parte de mi lógica ... y la respuesta de Ian Kemp tiene mucho más sentido ... Seguiré buscando en Google – Emir

+0

¡Gracias, por ejemplo, funciona! – Emir

1

Usted tendrá que convertir la cadena en una matriz byte[] (usando Encoding.Unicode.GetBytes(string)), a continuación, recorrer esa matriz y anteponer un carácter \ y u a todos los caracteres Unicode que encontrar. Cuando vuelva a convertir la matriz en una cadena, tendrá que dejar los caracteres Unicode como números.

Por ejemplo, si la matriz tiene el siguiente aspecto:

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

se convertiría en:

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

Hola, gracias por su respuesta, He intentado implementar su solución, desafortunadamente no está funcionando. Creo que es porque hay una diferencia entre la codificación de Codepoint y UTF16 (Encoding.Unicode) Me está sugiriendo que envíe bytes desde la codificación UTF16 donde se exceptúa Codepoint. (Y esto funciona para muchos personajes, pero no para todos) – Emir

+0

Esta respuesta también parece funcionar, Probablemente tuve un error en mi código cuando lo estaba probando. Gracias por su respuesta y su tiempo – Emir

+0

El único problema aquí es que cuando convierte a una matriz de bytes perderá su codificación. Lo mejor es dejarlo como UTF-16 y recorrerlo. – Brain2000

18

Código fijo de respuesta aceptada - añadió carácter especial escape, tal 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(); 
} 
0

Sobre la base de la especificación, aquí hay algo de código en Java que está probado 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 necesita agregar 2 caracteres (cerca del carácter Unicode o simplemente usar? En su lugar) después de descifrar el código. porque el Unicode ocupa 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 representación ANSI equivalente basado en la página actual de códigos ANSI. N representa el valor del carácter Unicode expresado como un número decimal. Esta palabra clave es seguida inmediatamente por caracteres equivalentes en representación ANSI. De esta forma, los lectores antiguos ignorarán la palabra clave \ uN y elegirá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 de \ ucN encontrado.

Al igual que con todas las palabras clave RTF, puede estar presente un espacio de terminación de palabra clave (antes de los caracteres ANSI) que no se cuenta en los caracteres para omitir. Aunque es probable que esto no ocurra (o se recomiende), una palabra clave \ bin, su argumento y los datos binarios que siguen se consideran un solo carácter para saltarse los objetivos. Si se encuentra un carácter delimitador de alcance RTF (es decir, un corsé de apertura o cierre) mientras se escanean datos que se pueden omitir, se considera que los datos que se pueden omitir finalizan antes que el delimitador. Esto hace posible que un lector realice una recuperación de error rudimentaria. Para incluir un delimitador RTF en datos que se pueden omitir, se debe representar utilizando el símbolo de control apropiado (es decir, escapado con una barra diagonal inversa) como en texto sin formato. Cualquier palabra o símbolo de control RTF se considera un solo carácter a los efectos de contar los caracteres que se pueden omitir.

Un escritor RTF, cuando encuentra un carácter Unicode sin el correspondiente carácter ANSI, debe dar como resultado \ uN seguido de la mejor representación ANSI que pueda gestionar. Además, si el carácter Unicode se traduce en una secuencia de caracteres ANSI con un recuento de bytes que difiere del Conteo de bytes de caracteres Unicode actual, debe emitir la palabra clave \ ucN antes de la palabra clave \ uN para notificar al lector del cambio.

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

Cuestiones relacionadas