iconv を使用して UTF-8 を MS-ANSI に変換できないのはなぜですか?

iconv を使用して UTF-8 を MS-ANSI に変換できないのはなぜですか?

ファイルを utf-8 から ms-ansi に変換しようとしています。

私が使う

  iconv -f UTF8 -t MS-ANSI// < data.txt

しかし、

  iconv: illegal input sequence at position 171359

これを調べると

 dd if=data.txt of=error.txt bs=1 count=10 skip=171359

私はこれを理解します:

 hexdump -C error.txt
 00000000  ef bb bf 38 3a 6e 61 09  38 3a                    |...8:na.8:|
 0000000a

ファイルは utf-8 ではありませんか? そうでない場合、iconv の代わりに何を使用すればよいですか?

答え1

$ printf '\xef\xbb\xbf' | uconv -x any-name
\N{ZERO WIDTH NO-BREAK SPACE}

これはバイト オーダー マークとしても使用される文字 (U+FEFF、UTF-8 で 3 バイトにエンコード) です。いずれにしても、その文字は MS-ANSI (iso8859-1 のスーパーセットである windows-1252 に付けられる不適切な名前) にはないため、変換できません。

BOM は、UTF16-LE と UTF16-BE (または CPU エンディアンネスの影響を受けるその他の非バイト エンコーディング) を区別するために (一部のテキストの先頭で) 使用されます。バイト順序の曖昧さがない UTF-8 では意味がありません。シングル バイト文字の文字セットである windows-1252 ではさらに意味がありません。「ゼロ幅のノーブレーク スペース」であるため、これは非表示であり、「ゼロ幅のスペース」文字のような単語の区切りプロパティもないため、完全に削除しても安全です。

zsh、または:bashksh93

sed $'s/\ufeff//g' < input | iconv -t windows-1252

いくつかの実装ではiconv、以下も使用できます。

iconv -t windows-1252//translit < input

//translitテキストを忠実に翻訳できない場合は近似値を使用します。その場合は、U+FEFF 文字を削除するだけです。

$ printf '\xef\xbb\xbf\x38\x3a\x6e\x61\x09\x38\x3a' |
    iconv -t windows-1252//translit | hd
00000000  38 3a 6e 61 09 38 3a                              |8:na.8:|
00000007

別の方法としては、次の方法があります。

iconv -t utf-16le | iconv -f utf-16 -t windows-1252

最初のiconv変換は BOM なしの UTF-16 リトルエンディアンに変換されますが、最初の U+FEFF によって実際の UTF-16 は BOM 付きになります。そのため、2 番目のiconv変換では、そのエンコードのバイト順序を決定するために使用される BOM が削除されますutf-16

関連情報