Comment afficher la chaîne unicode sur RTF (en utilisant C#)

j'essaie de sortir une chaîne unicode au format RTF. (à l'aide de c# et winforms)

wikipedia:

si une escape Unicode est nécessaire, le mot de contrôle u est utilisé, suivi d'un entier décimal signé de 16 bits donnant le nombre de codepoint Unicode. Pour le bénéfice des programmes sans support Unicode, ceci doit être suivi de la représentation la plus proche de ce caractère dans la page de code spécifiée. Par exemple, u1576? donnerait le La lettre arabe beh, spécifiant que les programmes plus anciens qui n'ont pas de support Unicode devraient le rendre comme un point d'interrogation à la place.

Je ne sais pas comment convertir le caractère Unicode en Unicode codepoint ("u1576"). La Conversion en UTF 8, UTF 16 et similaire est facile, mais je ne sais pas comment convertir en codepoint.

Scénario dans lequel j'utilise ceci:

  • j'ai lu le fichier RTF existant dans string (je lis modèle)
  • chaîne de caractères.remplacer # TOKEN# par MyUnicodeString (le modèle est peuplé de données)
  • écrire le résultat dans un autre fichier RTF.

Problème, surviennent lorsque des caractères Unicode est arrivé

17
demandé sur Jens Mühlenhoff 2009-09-02 18:23:40

4 réponses

pourvu que tous les personnages que vous traitez existent dans le Plan Multilingue De Base (il est peu probable que vous ayez besoin de plus), alors un simple encodage UTF-16 devrait suffire.

Wikipedia:

tous les points de code possibles à partir de U+0000 par U+10FFFF, à l'exception du code de la mère porteuse Points U+D800-U+DFFF (qui ne sont pas des personnages), sont uniquement cartographié par UTF-16 indépendamment du point de code actuel ou futur attribution ou utilisation de caractères.

l'exemple de programme suivant illustre ce que vous voulez faire:

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

le plus important est le Convert.ToUInt32(c) qui renvoie essentiellement la valeur du point de code pour le caractère en question. L'échappement RTF pour unicode nécessite une valeur unicode décimale. System.Text.Encoding.Unicode l'encodage correspond à UTF-16 selon la documentation MSDN.

26
répondu Eric Smith 2009-09-02 19:38:18

code Fixe à partir de la réponse acceptée - ajout de caractères spéciaux échappant, comme décrit dans ce lien

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();
}
20
répondu Hogan 2012-04-06 12:09:55

il Vous faudra convertir la chaîne byte[] array (à l'aide de Encoding.Unicode.GetBytes(string)), puis boucle ce tableau et prépare un \ et u caractère à tous les caractères Unicode que vous trouvez. Quand vous convertissez alors le tableau de nouveau à une chaîne, vous devez laisser les caractères Unicode comme des nombres.

Par exemple, si votre tableau ressemble à ceci:

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

devient:

// 5c = \, 75 = u
byte[] unicodeData = new byte[] { 0x5c, 0x75, 0x15, 0x76 };
1
répondu Ian Kemp 2009-09-02 14:38:46

basé sur la spécification, voici un certain code en java qui est testé et fonctionne:

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

ce qui est important, c'est que vous devez ajouter 2 caractères (proche du caractère unicode ou juste utiliser ? au lieu de cela) après le décodage échappé. parce que l'unicode occupe 2 octets.

La spécification dit aussi que vous devez utiliser la valeur négative si le point de code est supérieur à 32767, mais dans mon test, c'est très bien si vous n'utilisez pas la valeur négative.

Voici la spec:

\uN ce mot-clé représente un seul caractère Unicode qui n'a pas de représentation ANSI équivalente basée sur la page de code ANSI actuelle. N représente la valeur du caractère Unicode exprimée en nombre décimal. Ce mot-clé est immédiatement suivi de caractères équivalents dans la représentation ANSI. De cette façon, les vieux lecteurs ignoreront le mot-clé \uN et saisiront correctement la représentation ANSI. Lorsque ce mot-clé est rencontré, le lecteur devrait ignorer le prochain N les caractères, Où N correspond à la dernière valeur \ucN rencontrée.

comme pour tous les mots-clés RTF, un espace de fin de mot-clé peut être présent (avant les caractères ANSI) qui n'est pas compté dans les caractères à sauter. Bien qu'il soit peu probable que cela se produise (ou recommandé), un mot-clé \bin, son argument et les données binaires qui suivent sont considérés comme un caractère à éviter. Si un caractère de délimiteur de portée RTF (c'est-à-dire une barre d'ouverture ou de fermeture) est rencontré alors en scannant les données skippables, on considère que les données skippables sont terminées avant le délimiteur. Cela permet à un lecteur d'effectuer une récupération rudimentaire des erreurs. Pour inclure un délimiteur RTF dans les données skippables, il doit être représenté à l'aide du symbole de contrôle approprié (c'est-à-dire qu'il doit s'échapper avec un antislash) comme dans le texte. Tout mot ou symbole de contrôle RTF est considéré comme un caractère unique aux fins de compter les caractères saisissables.

un auteur RTF, quand il rencontre un caractère Unicode sans caractère ANSI correspondant, si la sortie \uN est suivie de la meilleure représentation ANSI qu'elle puisse gérer. En outre, si le caractère Unicode se traduit par un flux de caractères ANSI avec un nombre d'octets différent du nombre D'octets des caractères Unicode actuels, il doit émettre le mot-clé \ucN avant le mot-clé \uN pour aviser le lecteur du changement.

les mots de contrôle RTF acceptent généralement les nombres signés de 16 bits comme arguments. Pour cette raison, Unicode des valeurs supérieures à 32767 doivent être exprimées en nombre négatif

0
répondu Yongtao Wang 2016-07-11 00:15:03