2009-09-02 56 views
16

我試圖輸出unicode字符串到RTF格式。 (使用C#和WinForms)如何輸出unicode字符串到RTF(使用C#)

From wikipedia

如果需要Unicode轉義,控制字\用於U,接着是16位有符號十進制整數給出的Unicode編碼點數目。爲了沒有Unicode支持的程序的好處,這必須在指定的代碼頁中最接近這個字符的表示。例如,\ u1576?會給阿拉伯文字母beh,指定那些沒有Unicode支持的舊程序應該把它作爲問號來代替。

我不知道如何將Unicode字符轉換爲Unicode碼點(「\ u1576」)。 轉換爲UTF 8,UTF 16和類似的很容易,但我不知道如何轉換爲代碼點。在我使用這個

場景:

  • 我讀現有的RTF文件轉換成字符串(我讀模板)
  • #與string.replace#TOKEN與MyUnicodeString(模板填充數據)
  • 將結果寫入另一個RTF文件。

問題,出現在Unicode字符到達

回答

25

前提是所有你在Basic Multilingual Plane迎合存在的字符(這是不可能的你需要更多),那麼一個簡單的UTF-16編碼就足夠了。

百科:從U + 0000

所有可能的碼點通過U + 10FFFF,除了 替代代碼點U + D800-U + 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值。根據MSDN文檔,System.Text.Encoding.Unicode編碼對應於UTF-16。

+0

嗯,非常有趣的一點。如果那是真的,那麼在我的邏輯中有可能出現錯誤...而伊恩坎普的回答更有意義......我會繼續使用Google搜索 – Emir 2009-09-02 15:21:57

+0

謝謝你的例子,它的工作原理! – Emir 2009-09-03 10:51:56

1

您必須將字符串轉換爲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 }; 
+0

嗨,謝謝你的迴應, 我試圖實現你的解決方案,不幸的是它不工作。 我認爲這是因爲Codepoint和UTF16編碼(Encoding.Unicode)之間存在差異 您建議我從UTF16編碼中輸出除碼點外的字節。 (並且這適用於很多人物,但不是全部) – Emir 2009-09-02 15:18:53

+0

此答案也適用於工作, 當我測試它時,我的代碼中可能有一個錯誤。 謝謝你的回答和你的時間 – Emir 2009-09-03 11:06:32

+0

這裏唯一的問題是當你轉換爲一個字節數組時,你將失去你的編碼。最好將其保留爲UTF-16並循環播放。 – Brain2000 2016-08-02 21:24:43

18

從接受的答案固定碼 - 添加特殊字符轉義,如本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

根據說明書中所述,這裏有一些Java代碼的測試和工程:

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字符或者只是使用?代替)在轉義的uncode之後。因爲unicode佔用2個字節。

此外,規範說如果代碼點大於32767,你應該使用負值,但在我的測試中,如果你不使用負值,那就沒問題。

這裏是規格:

\ UN此關鍵字表示具有根據當前ANSI代碼頁上沒有等效ANSI表示一個單一的Unicode字符。 N表示以十進制數表示的Unicode字符值。 此關鍵字後面跟着ANSI代碼中的等效字符。這樣,老的讀者會忽略\ uN關鍵詞並正確地選取ANSI表示。遇到這個關鍵字時,讀者應忽略接下來的N個字符,其中N對應於遇到的最後一個\ ucN值。

與所有RTF關鍵字一樣,關鍵字終止空間可能存在(ANSI字符之前),這些空間不包括在要跳過的字符中。雖然這不太可能發生(或推薦),但\ bin關鍵字,其參數以及後面的二進制數據被認爲是用於跳過目的的一個字符。如果在掃描可跳過的數據時遇到RTF作用域分隔符(即打開或關閉大括號),則可跳過的數據被視爲在分隔符之前結束。這使讀者可以執行一些基本的錯誤恢復。要在可跳過的數據中包含RTF分隔符,必須使用適當的控制符號(即,用反斜槓轉義)以純文本形式表示它。任何RTF控制字或符號被視爲用於計算可跳過字符的單個字符。

一個RTF編寫器,當它遇到一個沒有相應的ANSI字符的Unicode字符時,應該輸出\ uN,後面跟着它可以管理的最好的ANSI表示。另外,如果Unicode字符轉換爲字符數與當前Unicode字符字節數不同的ANSI字符流,則應在\ uN關鍵字之前發出\ ucN關鍵字以通知讀者該更改。

RTF控制字通常接受帶符號的16位數作爲參數。由於這個原因,Unicode值大於32767必須表示爲負數