代码之家  ›  专栏  ›  技术社区  ›  Emir

如何将unicode字符串输出到rtf(使用c)

  •  19
  • Emir  · 技术社区  · 15 年前

    我正在尝试将Unicode字符串输出为RTF格式。(使用C和WinForms)

    From wikipedia :

    如果需要Unicode转义,则使用控制字\u,后跟一个16位带符号十进制整数,给出Unicode码位号。为了使不支持Unicode的程序受益,后面必须跟指定代码页中该字符的最近表示。例如,1576?将给出阿拉伯字母beh,指定不支持Unicode的旧程序应将其作为问号呈现。

    我不知道如何将Unicode字符转换为Unicode码位(“\u1576”)。 转换为UTF 8、UTF 16和类似的代码很容易,但我不知道如何转换为代码点。

    我使用这个的场景:

    • 我将现有的RTF文件读取为字符串(我正在读取模板)
    • string.replace token with myunicodestring(模板由数据填充)
    • 将结果写入另一个RTF文件。

    当Unicode字符到达时出现问题

    4 回复  |  直到 8 年前
        1
  •  27
  •   Eric Smith    15 年前

    前提是你要为之服务的所有角色都存在于 Basic Multilingual Plane (您不太可能需要更多的内容),那么一个简单的UTF-16编码就足够了。

    维基百科:

    U+0000的所有可能代码点 通过U+10ffff,除了 代理代码点U+D800U+DFFF (不是字符)是 由UTF-16唯一映射,无论 代码点的当前或未来 字符分配或使用。

    下面的示例程序说明了如何按照您想要的方式执行某些操作:

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

    重要的一点是 Convert.ToUInt32(c) 它实质上返回所讨论字符的代码点值。Unicode的RTF转义需要十进制Unicode值。这个 System.Text.Encoding.Unicode 根据msdn文档,编码对应于utf-16。

        2
  •  21
  •   Hogan    12 年前

    修正了接受答案的代码-添加了特殊字符转义,如本文所述 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();
    }
    
        3
  •  1
  •   Ian Kemp    15 年前

    必须将字符串转换为 byte[] 数组(使用) Encoding.Unicode.GetBytes(string) ,然后循环遍历该数组并预处理 \ u 字符转换为您找到的所有Unicode字符。然后将数组转换回字符串时,必须将Unicode字符保留为数字。

    例如,如果数组如下所示:

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

    它将成为:

    // 5c = \, 75 = u
    byte[] unicodeData = new byte[] { 0x5c, 0x75, 0x15, 0x76 };
    
        4
  •  0
  •   Yongtao Wang    8 年前

    基于规范,这里有一些代码在爪哇进行测试和工作:

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

    重要的是,您需要附加2个字符(接近Unicode字符还是只使用?相反)在逃走后解开。因为Unicode占用2个字节。

    另外,规范还说,如果代码点大于32767,则应该使用负值,但是在我的测试中,如果不使用负值,则可以。

    规格如下:

    \ un此关键字表示一个Unicode字符,该字符没有基于当前ANSI代码页的等效ANSI表示。n表示以十进制数表示的Unicode字符值。 在ANSI表示形式中,此关键字后紧跟等效字符。通过这种方式,旧的读卡器将忽略\n un关键字,并正确地获取ansi表示。遇到此关键字时,读卡器应忽略后面的n个字符,其中n对应于遇到的最后一个\ucn值。

    与所有rtf关键字一样,关键字终止空格可能存在(在ansi字符之前),不计入要跳过的字符中。虽然这不太可能发生(或建议发生),但\bin关键字、其参数和后面的二进制数据被视为一个字符,用于跳过目的。如果在扫描可跳过数据时遇到RTF作用域分隔符字符(即左大括号或右大括号),则认为可跳过数据在分隔符之前结束。这使得读卡器可以执行一些基本的错误恢复。要在可跳过数据中包含RTF分隔符,必须使用适当的控制符号(即,用反斜杠转义)表示,如纯文本中所示。为了计算可跳过字符,任何RTF控制字或符号都被视为单个字符。

    RTF编写器在遇到没有相应的ANSI字符的Unicode字符时,应该输出\n后跟它可以管理的最佳ANSI表示形式。此外,如果unicode字符转换为一个字节数与当前unicode字符字节数不同的ansi字符流,它应该在un关键字之前发出\ucn关键字来通知读卡器更改。

    RTF控制字通常接受有符号的16位数字作为参数。因此,大于32767的Unicode值必须表示为负数。