web-dev-qa-db-ja.com

iconvを使用してUTF8をUTF16に変換する

Iconvを使用してUTF16からUTF8に変換すると、すべては問題ありませんが、その逆は機能しません。これらのファイルがあります:

a-16.strings:    Little-endian UTF-16 Unicode c program text
a-8.strings:     UTF-8 Unicode c program text, with very long lines

テキストはエディターでOKに見えます。これを実行すると:

iconv -f UTF-8 -t UTF-16LE a-8.strings > b-16.strings

次に、この結果が得られます:

b-16.strings:    data
a-16.strings:    Little-endian UTF-16 Unicode c program text
a-8.strings:     UTF-8 Unicode c program text, with very long lines

fileユーティリティは、期待されるファイル形式を表示せず、テキストもエディターで適切に表示されません。 iconvが適切なBOMを作成しないのでしょうか? MACコマンドラインで実行します。

なぜb-16は適切なUTF-16LE形式ではないのですか? utf8をutf16に変換する別の方法はありますか?

さらに詳しく説明します。

$ iconv -f UTF-8 -t UTF-16LE a-8.strings > b-16le-BAD-fromUTF8.strings
$ iconv -f UTF-8 -t UTF-16 a-8.strings > b-16be.strings 
$ iconv -f UTF-16 -t UTF-16LE b-16be.strings > b-16le-BAD-fromUTF16BE.strings

$ file *s
a-16.strings:                   Little-endian UTF-16 Unicode c program text, with very long lines
a-8.strings:                    UTF-8 Unicode c program text, with very long lines
b-16be.strings:                 Big-endian UTF-16 Unicode c program text, with very long lines
b-16le-BAD-fromUTF16BE.strings: data
b-16le-BAD-fromUTF8.strings:    data


$ od -c a-16.strings | head
0000000  377 376   /  \0   *  \0      \0  \f 001   E  \0   S  \0   K  \0

$ od -c a-8.strings | head 
0000000    /   *   *   *       Č  **   E   S   K   Y       (   J   V   O

$ od -c b-16be.strings | head
0000000  376 377  \0   /  \0   *  \0   *  \0   *  \0     001  \f  \0   E

$ od -c b-16le-BAD-fromUTF16BE.strings | head                                
0000000    /  \0   *  \0   *  \0   *  \0      \0  \f 001   E  \0   S  \0

$ od -c b-16le-BAD-fromUTF8.strings | head
0000000    /  \0   *  \0   *  \0   *  \0      \0  \f 001   E  \0   S  \0

UTF-16LEへの変換を実行するたびにBOMが欠落していることは明らかです。これについて何か助けがありますか?

UTF-16LEは、リトルエンディアンUTF-16withoutBOM(バイトオーダーマーク)を生成するようiconvに指示します。 LEを指定したため、BOMは必要ないと思われます。

UTF-16は、(ローカルマシンのバイトオーダーで)UTF-16テキストを生成するように指示しますwithBOM。

リトルエンディアンのマシンを使用している場合、iconvにBOMを使用してビッグエンディアンUTF-16を生成するように指示する方法はありませんが、何か不足している可能性があります。

fileコマンドはBOMなしのUTF-16テキストを認識せず、エディターもそうでない可能性があります。ただし、iconv -f UTF-16LE -t UTF_8 b-16 stringsを実行する場合は、元のファイルの有効なUTF-8バージョンを取得する必要があります。

ファイルでod -cを実行して、実際の内容を確認してください。

PDATE:

ビッグエンディアンのマシン(x86はリトルエンディアン)で、BOMを使用してリトルエンディアンUTF-16ファイルを生成しようとしているようです。あれは正しいですか?私が知る限り、iconvはそれを直接行いません。しかし、これは動作するはずです:

( printf "\xff\xfe" ; iconv -f utf-8 -t utf-16le UTF-8-FILE ) > UTF-16-FILE

printfmightの動作は、ロケール設定に依存します。 LANG=en_US.UTF-8があります。

(誰もがよりエレガントなソリューションを提案できますか?)

別の回避策、if-t utf-16によって生成される出力のエンディアンを知っている場合:

iconv -f utf-8 -t utf-16 UTF-8-FILE | dd conv=swab 2>/dev/null
36
Keith Thompson

最初にUTF-16に変換します。これは、必要に応じてバイト順マークを付加します Keith Thompsonが述べているようにUTF-16はエンディアンを定義しないため、fileを使用して、UTF-16BEUTF-16LEかを判断する必要があります。最後に、UTF-16LEに変換できます。

iconv -f utf-8 -t utf-16 UTF-8-FILE > UTF-16-UNKNOWN-ENDIANNESS-FILE
FILE_ENCODING="$( file --brief --mime-encoding UTF-16-UNKNOWN-ENDIANNESS-FILE )"
iconv -f "$FILE_ENCODING" -t UTF-16LE UTF-16-UNKNOWN-ENDIANNESS-FILE > UTF-16-FILE
3
Heath Borders

これはエレガントな解決策ではないかもしれませんが、このスレッドの主題に似ていると思われる私の問題の正しい変換を確実にするための手動の方法を見つけました。

問題:ユーザーからテキストデータファイルを取得し、シェルスクリプト(トークン化、分割など)を使用してLinux(具体的にはUbuntu)で処理します。ファイルをmyfile.txtと呼びましょう。何かがおかしいとわかった最初の兆候は、トークン化が機能していなかったことです。 myfile.txtfileコマンドを実行して次のようになったとき、私は驚きませんでした

$ file myfile.txt

myfile.txt: Little-endian UTF-16 Unicode text, with very long lines, with CRLF line terminators

ファイルが準拠している場合、会話は次のようになります。

$ file myfile.txt

myfile.txt: ASCII text, with very long lines

解決策:データファイルを準拠させるために、他の手順で試行錯誤を繰り返した結果、3つの手動手順が機能することがわかりました。

  1. 最初に、vi(またはvim)を介して同じエンコーディングでビッグエンディアンに変換します。 vi myfile.txtvi:set fileencoding=UTF-16BEを実行し、ファイルを書き出します。 :!wqで強制する必要があるかもしれません。

  2. vi myfile.txt(utf-16BEになりました)。 vi:set fileencoding=ASCIIを実行し、ファイルを書き出します。繰り返しますが、!wqを使用して書き込みを強制する必要がある場合があります。

  3. dos2unixコンバーターを実行します:d2u myfile.txtfile myfile.txtを実行すると、出力が表示されるか、より身近で確実なものが表示されるはずです。

    myfile.txt: ASCII text, with very long lines
    

それでおしまい。それが私にとってはうまくいったので、myfile.txtの処理bashシェルスクリプトを実行することができました。ステップ2をスキップできないことがわかりました。つまり、この場合、ステップ3に直接スキップすることはできません。この情報が役立つことを願っています。おそらくsedなどを介して誰かがそれを自動化できることを願っています。乾杯。

0
Adams