23

Unicode 文字列を RTF 形式で出力しようとしています。(c# と winform を使用)

ウィキペディアから

Unicode エスケープが必要な場合は、制御語 \u が使用され、その後に Unicode コードポイント番号を示す 16 ビットの符号付き 10 進整数が続きます。Unicode をサポートしないプログラムのために、指定されたコード ページでのこの文字の最も近い表現がこの後に続く必要があります。たとえば、\u1576? Unicode をサポートしていない古いプログラムでは、代わりに疑問符としてレンダリングする必要があることを指定して、アラビア文字 beh を指定します。

Unicode 文字を Unicode コードポイント ("\u1576") に変換する方法がわかりません。UTF 8 や UTF 16 などへの変換は簡単ですが、codepoint への変換方法がわかりません。

私がこれを使用するシナリオ:

  • 既存の RTF ファイルを文字列に読み込みます (テンプレートを読み込んでいます)
  • string.replace #TOKEN# を MyUnicodeString に置き換えます (テンプレートにデータが入力されます)
  • 結果を別の RTF ファイルに書き込みます。

問題、Unicode 文字が到着したときに発生

4

4 に答える 4

29

ケータリング対象のすべての文字がBasic Multilingual Planeに存在する場合(それ以上必要になる可能性はほとんどありません)、単純な UTF-16 エンコーディングで十分です。

ウィキペディア:

サロゲート コード ポイント U+D800–U+DFFF (文字ではない) を除き、U+0000 から U+10FFFF までの可能なすべてのコード ポイントは、コード ポイントの現在または将来の文字割り当てに関係なく、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 エスケープには、10 進数の Unicode 値が必要です。エンコーディングはSystem.Text.Encoding.Unicode、MSDN ドキュメントによると UTF-16 に対応しています。

于 2009-09-02T14:39:12.960 に答える
26

受け入れられた回答からの修正されたコード-このリンクで説明されているように、特殊文字のエスケープが追加されました

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();
}
于 2012-04-03T07:11:21.807 に答える
2

byte[]文字列を( を使用して) 配列に変換し、Encoding.Unicode.GetBytes(string)その配列をループして、見つかったすべての Unicode 文字の先頭に文字\u文字を追加する必要があります。その後、配列を文字列に戻すときは、Unicode 文字を数値のままにしておく必要があります。

たとえば、配列が次のようになっているとします。

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

それは次のようになります。

// 5c = \, 75 = u
byte[] unicodeData = new byte[] { 0x5c, 0x75, 0x15, 0x76 };
于 2009-09-02T14:38:46.657 に答える
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();
 }

重要なことは、エスケープされた uncode の後に 2 文字 (Unicode 文字に近いか、代わりに ? を使用する) を追加する必要があることです。Unicode は 2 バイトを占めるためです。

また、仕様では、コード ポイントが 32767 より大きい場合は負の値を使用する必要があると記載されていますが、私のテストでは、負の値を使用しなくても問題ありません。

仕様は次のとおりです。

\uN このキーワードは、現在の ANSI コード ページに基づく同等の ANSI 表現を持たない単一の Unicode 文字を表します。N は、10 進数で表された Unicode 文字値を表します。このキーワードの直後には、ANSI 表記の同等の文字が続きます。このようにして、古い読者は \uN キーワードを無視し、ANSI 表現を適切に取得します。このキーワードが検出されると、リーダーは次の N 文字を無視する必要があります。ここで、N は検出された最後の \ucN 値に対応します。

すべての RTF キーワードと同様に、スキップする文字にカウントされないキーワード終了スペース (ANSI 文字の前) が存在する場合があります。これが発生する可能性は低い (または推奨される) ものの、\bin キーワード、その引数、およびそれに続くバイナリ データは、スキップのために 1 文字と見なされます。スキップ可能なデータのスキャン中に RTF スコープ区切り文字 (つまり、開き中かっこまたは閉じ中かっこ) が検出された場合、スキップ可能なデータは区切り文字の前で終了していると見なされます。これにより、リーダーは初歩的なエラー回復を実行できます。スキップ可能なデータに RTF 区切り文字を含めるには、プレーン テキストと同様に適切な制御記号を使用して (つまり、バックスラッシュでエスケープして) 表す必要があります。RTF 制御語またはシンボルは、スキップ可能な文字をカウントする目的で 1 文字と見なされます。

RTF ライターは、対応する ANSI 文字のない Unicode 文字に遭遇した場合、\uN に続いて管理できる最適な ANSI 表現を出力する必要があります。また、Unicode 文字が現在の Unicode Character Byte Count とは異なるバイト数を持つ ANSI 文字ストリームに変換される場合、\uN キーワードの前に \ucN キーワードを発行して、リーダーに変更を通知する必要があります。

RTF 制御ワードは通常、符号付き 16 ビット数値を引数として受け入れます。このため、32767 より大きい Unicode 値は負の数で表す必要があります。

于 2016-07-11T00:15:03.930 に答える