Unicode文字列をRTF形式で出力しようとしています。(c#とwinformsを使用)
Unicodeエスケープが必要な場合は、制御ワード\ uが使用され、その後にUnicodeコードポイント番号を与える16ビットの符号付き10進整数が続きます。 Unicodeをサポートしていないプログラムの利益のために、これの後に、指定されたコードページでこの文字の最も近い表現を続ける必要があります。たとえば、\ u1576? Unicodeをサポートしていない古いプログラムは、代わりに疑問符としてレンダリングする必要があることを指定して、アラビア文字のbehを与えます。
Unicode文字をUnicodeコードポイント( "\ u1576")に変換する方法がわかりません。 UTF 8、UTF 16などへの変換は簡単ですが、コードポイントに変換する方法がわかりません。
私がこれを使用するシナリオ:
問題、Unicode文字が到着したときに発生します
ケータリングしているすべての文字が 基本的な多言語プレーン (これ以上必要になる可能性は低いです)に存在する場合は、単純な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)
であり、これは基本的に問題の文字のコードポイント値を返します。ユニコードのRTFエスケープには、10進数のユニコード値が必要です。_System.Text.Encoding.Unicode
_エンコーディングは、MSDNドキュメントのUTF-16に対応しています。
受け入れられた回答からのコードを修正しました-これで説明されているように、特殊文字のエスケープを追加しました リンク
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();
}
文字列を_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 };
_
仕様に基づいて、次のコードが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文字を追加する必要があることです(ユニコード文字に近いか、代わりに?を使用してください)。ユニコードが2バイトを占めるためです。
また、仕様では、コードポイントが32767より大きい場合は負の値を使用する必要があると規定されていますが、私のテストでは、負の値を使用しない場合は問題ありません。
仕様は次のとおりです。
\ uNこのキーワードは、現在のANSIコードページに基づく同等のANSI表現を持たない単一のUnicode文字を表します。 Nは、10進数で表されるUnicode文字値を表します。このキーワードの直後には、ANSI表現の同等の文字が続きます。このようにして、古い読者は\ uNキーワードを無視し、ANSI表現を適切に取得します。このキーワードが検出された場合、リーダーは次のN文字を無視する必要があります。Nは最後に検出された\ ucN値に対応します。
すべてのRTFキーワードと同様に、スキップする文字にカウントされないキーワード終了スペースが(ANSI文字の前に)存在する場合があります。これは発生しない可能性があります(または推奨されます)。 、\ binキーワード、その引数、およびそれに続くバイナリデータは、スキップの目的で1文字と見なされます。RTFスコープ区切り文字(つまり、開始または終了中括弧)が検出された場合スキップ可能なデータをスキャンしている間、スキップ可能なデータは区切り文字の前で終了していると見なされます。これにより、リーダーは基本的なエラー回復を実行できます。RTF区切り文字をスキップ可能なデータに含めるには、プレーンテキストのように、適切な制御記号を使用して(つまり、バックスラッシュでエスケープして)表す必要があります。任意のRTF制御単語または記号は、スキップ可能な文字をカウントするために単一の文字と見なされます。 。
RTFライターは、対応するANSI文字のないUnicode文字を検出すると、\ uNに続いて、管理できる最高のANSI表現を出力する必要があります。また、Unicode文字がANSI文字に変換される場合現在のUnicode文字のバイト数とは異なるバイト数のストリームの場合、リーダーに変更を通知するために、\ uNキーワードの前に\ ucNキーワードを発行する必要があります。
RTF制御ワードは通常、符号付き16ビット数を引数として受け入れます。このため、32767より大きいUnicode値は負の数として表現する必要があります