大量のファイルをUS-ASCIIからUTF-8にトランスコードしようとしています。
そのために、私はiconvを使用しています:
iconv -f US-ASCII -t UTF-8 file.php > file-utf8.php
元のファイルはUS-ASCIIでエンコードされているため、変換は行われません。 ASCIIはUTF-8のサブセットです...
そして引用:
非ASCII文字が導入されるまで、テキストファイルを表示する必要はありません。
本当です。ファイルに非ASCII文字を導入して保存すると、Eclipseの場合、ファイルエンコーディング(文字セット)がUTF-8に切り替わります。
私の場合、とにかくiconvにファイルをUTF-8にトランスコードさせます。非ASCII文字が含まれているかどうか。
注:理由は、私のPHPコード(非ASCIIファイル...)が非ASCII文字列を処理しているため、文字列が適切に解釈されない(フランス語)ためです。
Ilétait une fois ... l'hommesérieanimée mythique d'Albert
Barillé(Procidis)、1ère
...
編集
US-ASCII
-is-UTF-8
のサブセット(下記の Nedの答え を参照)US-ASCII
ファイルが実際にUTF-8
でエンコードされているという意味ASCIIはUTF-8のサブセットであるため、すべてのASCIIファイルはすでにUTF-8エンコードされています。 ASCIIファイル内のバイトと「UTF-8にエンコード」した結果として生じるバイトは、まったく同じバイトになります。それらの間に違いはないので、何もする必要はありません。
問題は、ファイルが実際にはASCIIではないことです。使用しているエンコーディングを判断し、適切にトランスコードする必要があります。
file
は、ファイルエンコーディングを推測するだけで、間違っている可能性があります(特に、大きなファイルで特殊文字が遅れて表示される場合)。hexdump
を使用して、7ビットASCII以外のテキストのバイトを調べ、一般的なエンコード(iso-8859-*、utf-8)のコードテーブルと比較して、エンコードが何であるかを自分で決定できます。iconv
は、ファイルの内容に関係なく、指定した入力/出力エンコーディングを使用します。間違った入力エンコーディングを指定すると、出力が文字化けします。iconv
を実行した後でも、file
がエンコードを推測しようとする方法が限られているため、file
は変更を報告しない場合があります。具体的な例については、私の長い答えをご覧ください。今日私はこれに遭遇し、あなたの質問に出会いました。おそらく、この問題に遭遇した他の人々を支援するために、もう少し情報を追加できます。
まず、用語ASCIIはオーバーロードされており、混乱を招きます。
7ビットASCIIには128文字(00-7Fまたは10進数で0-127)のみが含まれます。 7ビットASCIIはUS-ASCIIとも呼ばれます。
https://en.wikipedia.org/wiki/ASCII
UTF-8エンコードは、最初の128文字に7ビットASCIIと同じエンコードを使用します。したがって、最初の128文字のその範囲の文字のみを含むテキストファイルは、UTF-8でエンコードされているか7ビットASCIIでエンコードされているかにかかわらず、バイトレベルで同一になります。
https://en.wikipedia.org/wiki/UTF-8#Codepage_layout
extended ascii(またはhigh ascii)という用語は、標準の7ビット_を含む8ビット以上の文字エンコーディングを指します。ASCII文字、および追加の文字。
https://en.wikipedia.org/wiki/Extended_ASCII
ISO-8859-1(別名「ISO Latin 1」)は、西ヨーロッパのほとんどの文字をカバーする特定の8ビットASCII拡張標準です。東ヨーロッパ言語およびキリル言語には他のISO標準があります。 ISO-8859-1には、ドイツ語とスペイン語のÖ、é、ñ、ßなどの文字が含まれています。 「拡張」とは、ISO-8859-1に7ビットASCII標準が含まれ、8ビット目を使用して文字が追加されることを意味します。したがって、最初の128文字については、バイトレベルでASCIIおよびUTF-8エンコードファイルと同等です。ただし、最初の128を超える文字の処理を開始すると、バイトレベルでUTF-8と同等ではなくなり、「拡張ASCII」ファイルをUTF-8エンコードする場合は変換を行う必要があります。
https://en.wikipedia.org/wiki/Extended_ASCII#ISO_8859_and_proprietary_adaptations
今日学んだ1つの教訓は、ファイルの文字エンコーディングの正しい解釈を常に与えるためにfile
を信頼できないことです。
https://en.wikipedia.org/wiki/File_%28command%29
このコマンドは、ファイルが何であるかだけを示し、ファイルが何であるかを示しません(ファイルがコンテンツを見る場合)。内容が一致しないファイルにマジックナンバーを挿入することで、プログラムをだますのは簡単です。したがって、コマンドは特定の状況以外ではセキュリティツールとして使用できません。
file
はファイル内で型を暗示するマジックナンバーを探しますが、これらは間違っている可能性があり、正確性を保証するものではありません。 file
は、ファイル内のバイトを調べることで文字エンコードを推測しようとします。基本的にfile
には、ファイルの種類とエンコーディングを推測するのに役立つ一連のテストがあります。
私のファイルは大きなCSVファイルです。 file
は、このファイルをus-asciiエンコードとして報告します。これはWRONGです。
$ ls -lh
total 850832
-rw-r--r-- 1 mattp staff 415M Mar 14 16:38 source-file
$ file -b --mime-type source-file
text/plain
$ file -b --mime-encoding source-file
us-ascii
私のファイルにはウムラウトが含まれています(つまりÖ)。最初の非7ビットASCIIは、ファイルに10万行を超えるまで表示されません。これが、file
がファイルエンコーディングがUS-ASCIIでないことを認識しない理由だと思います。
$ pcregrep -no '[^\x00-\x7F]' source-file | head -n1
102321:�
私はMacにいるので、PCREのgrep
を使用しています。 gnu grepでは、-P
オプションを使用できます。あるいは、Mac上で、gnu grepを取得するためにcoreutilsを(homebrewなどを介して)インストールできます。
file
のソースコードを掘り下げたことはなく、マニュアルページではテキストエンコーディングの検出について詳しく説明していませんが、エンコーディングを推定する前にfile
がファイル全体を調べていないと推測しています。
ファイルのエンコーディングが何であれ、これらの非7ビットASCII文字は問題を引き起こします。ドイツのCSVファイルは;
- separatedであり、単一の列の抽出は機能しません。
$ cut -d";" -f1 source-file > tmp
cut: stdin: Illegal byte sequence
$ wc -l *
3081673 source-file
102320 tmp
3183993 total
cut
エラーと、「tmp」ファイルには102320行しかなく、最初の特殊文字が102321行にあることに注意してください。
これらの非ASCII文字がどのようにエンコードされるかを見てみましょう。最初の非7ビットASCIIをhexdump
にダンプし、少し書式設定を行い、改行(0a
)を削除して、最初の数行のみを取得します。
$ pcregrep -o '[^\x00-\x7F]' source-file | head -n1 | hexdump -v -e '1/1 "%02x\n"'
d6
0a
別の方法。最初の非7ビットASCII文字が行102321の85の位置にあることを知っています。その行を取得し、hexdump
に位置85から始まる2バイトを取るように指示します。特別な(非7ビットASCII ) "。"で表される文字で、次のバイトは "M" ...ですので、これは1バイト文字エンコードです。
$ tail -n +102321 source-file | head -n1 | hexdump -C -s85 -n2
00000055 d6 4d |.M|
00000057
どちらの場合でも、特殊文字はd6
で表されます。この文字はÖ(ドイツ語の文字)であるため、ISO-8859-1はこれを含めるべきだと推測しています。確かに、「d6」が一致することがわかります( https://en.wikipedia.org/wiki/ISO/IEC_8859-1#Codepage_layout )。
重要な質問...この文字がファイルエンコーディングを確認せずにÖであることを確認するにはどうすればよいですか?答えは文脈です。ファイルを開いてテキストを読み、それがどの文字であるかを判断しました。 vim
で開くと、Öとして表示されます。なぜなら、vim
は、file
よりも文字エンコード(この場合)のguessingの方が優れているからです。
したがって、私のファイルはISO-8859-1のようです。理論的には、非7ビットASCII文字の残りをチェックして、ISO-8859-1が適切であることを確認する必要があります...ファイルを書き込むときに、プログラムが単一のエンコーディングのみを使用するよう強制するものはありません。ディスク(マナー以外)。
チェックをスキップして、変換手順に進みます。
$ iconv -f iso-8859-1 -t utf8 source-file > output-file
$ file -b --mime-encoding output-file
us-ascii
うーん。 file
は、変換後でもこのファイルがUS-ASCIIであることを示しています。もう一度hexdump
で確認しましょう。
$ tail -n +102321 output-file | head -n1 | hexdump -C -s85 -n2
00000055 c3 96 |..|
00000057
間違いなく変更。 2バイトの非7ビットASCII(右側の「。」で表される)があり、2バイトの16進コードがc3 96
になっていることに注意してください。見てみると、UTF-8を持っているようです(c3 96はUTF-8でのÖの正しいエンコーディングです) http://www.utf8-chartable.de/
しかし、file
はまだファイルをus-ascii
として報告しますか?まあ、これはfile
がファイル全体を見ていないという点と、最初の非7ビットASCII文字がファイルの奥まで発生しないという点に戻っていると思います。
sed
を使用してファイルの先頭にÖを付け、何が起こるかを確認します。
$ sed '1s/^/Ö\'$'\n/' source-file > test-file
$ head -n1 test-file
Ö
$ head -n1 test-file | hexdump -C
00000000 c3 96 0a |...|
00000003
いいですね、ウムラウトがあります。ただし、エンコードはc3 96(utf-8)であることに注意してください。うーん。
同じファイル内の他のウムラウトを再度確認します。
$ tail -n +102322 test-file | head -n1 | hexdump -C -s85 -n2
00000055 d6 4d |.M|
00000057
ISO-8859-1。おっと!エンコーディングをめちゃくちゃにするのがいかに簡単かを示すだけです。
前にウムラウトを付けて新しいテストファイルを変換し、何が起こるか見てみましょう。
$ iconv -f iso-8859-1 -t utf8 test-file > test-file-converted
$ head -n1 test-file-converted | hexdump -C
00000000 c3 83 c2 96 0a |.....|
00000005
$ tail -n +102322 test-file-converted | head -n1 | hexdump -C -s85 -n2
00000055 c3 96 |..|
00000057
おっと。 UTF-8であった最初のウムラウトは、それがiconv
に伝えたことであるため、ISO-8859-1として解釈されました。 2番目のウムラウトは、d6
からc3 96
に正しく変換されます。
もう一度試してみますが、今回はvim
の代わりにsed
を使用してÖ挿入を行います。 vim
はエンコードをよりよく検出するように見えた(「latin1」、別名ISO-8859-1)ので、おそらく一貫したエンコードで新しいÖを挿入するでしょう。
$ vim source-file
$ head -n1 test-file-2
�
$ head -n1 test-file-2 | hexdump -C
00000000 d6 0d 0a |...|
00000003
$ tail -n +102322 test-file-2 | head -n1 | hexdump -C -s85 -n2
00000055 d6 4d |.M|
00000057
いいね。新しいウムラウトと古いウムラウトのISO-8859-1のように見えます。
今テスト。
$ file -b --mime-encoding test-file-2
iso-8859-1
$ iconv -f iso-8859-1 -t utf8 test-file-2 > test-file-2-converted
$ file -b --mime-encoding test-file-2-converted
utf-8
ブーム!この話の教訓。 file
を信頼して、常にエンコーディングの権利を推測しないでください。同じファイル内でエンコードを簡単に混在させることができます。疑わしいときは、ヘックスを見てください。
大きなファイルを処理する際にfile
のこの特定の制限に対処するハック(失敗しやすい)は、ファイルを短くして、特殊文字がファイルの初期に現れるようにすることで、file
がそれらを見つけやすくなります。
$ first_special=$(pcregrep -o1 -n '()[^\x00-\x7F]' source-file | head -n1 | cut -d":" -f1)
$ tail -n +$first_special source-file > /tmp/source-file-shorter
$ file -b --mime-encoding /tmp/source-file-shorter
iso-8859-1
Christos Zoulasはfile
を更新して、見られるバイト数を設定可能にしました。ある日、機能のリクエストのターンアラウンド、素晴らしい!
http://bugs.gw.com/view.php?id=5https://github.com/file/file/commit/d04de269e0b06ccd0a7d1bf4974fed1d75be7d9e
この機能は、file
バージョン5.26でリリースされました。
エンコードについて推測する前に、より大きなファイルを確認するには時間がかかります。ただし、特定のユースケースでは、より正確な推測が追加の時間/ IOを上回る可能性があるため、オプションがあると便利です。
次のオプションを使用します。
−P, −−parameter name=value
Set various parameter limits.
Name Default Explanation
bytes 1048576 max number of bytes to read from file
何かのようなもの...
file_to_check="myfile"
bytes_to_scan=$(wc -c < $file_to_check)
file -b --mime-encoding -P bytes=$bytes_to_scan $file_to_check
...推測する前にfile
にファイル全体を強制的に表示させたい場合は、このトリックを行う必要があります。もちろん、これはfile
5.26以降を使用している場合にのみ機能します。
私はまだ最新のリリースをビルド/テストしていません。私のマシンのほとんどには、現在file
5.04(2010)があります...いつかこのリリースでアップストリームからダウンすることを願っています。
だから人々はあなたができないと言うし、私はあなたが質問をしてそのような答えを得るときにあなたがイライラするかもしれないことを理解しています。
Us-asciiではなくutf-8で表示したい場合は、2ステップで行う必要があります。
最初 :
iconv -f us-ascii -t utf-16 yourfile > youfileinutf16.*
2番目:
iconv -f utf-16le -t utf-8 yourfileinutf16 > yourfileinutf8.*
ファイル-iを実行すると、新しい文字セットがutf-8であることがわかります。
それが役に立てば幸い。
Nedが問題の核心を持っている -あなたのファイルは実際にはASCIIではない。試してみる
iconv -f ISO-8859-1 -t UTF-8 file.php > file-utf8.php
私はあなたが実際に iso-8859-1 を使用していると推測していますが、ほとんどのヨーロッパ言語で人気があります。
US-ASCIIとUTF-8に違いはないため、再変換する必要はありません。ただし、再コーディング中に特殊文字に問題がある場合は、ここに少しヒントを示します。
Source-charset-Parameterの後に// TRANSLITを追加します。
例:
iconv -f ISO-8859-1//TRANSLIT -t UTF-8 filename.sql > utf8-filename.sql
これは、文字セットの再エンコードプロセスを常に壊してしまう、奇妙なタイプの引用に役立ちます。
次に、渡すパターンに一致するすべてのファイルを検索し、現在のファイルエンコーディングからutf-8に変換するスクリプトを示します。エンコードがus-asciiの場合、utf-8のサブセットであるため、us-asciiとして表示されます。
#!/usr/bin/env bash
find . -name "${1}" |
while read line;
do
echo "***************************"
echo "Converting ${line}"
encoding=$(file -b --mime-encoding ${line})
echo "Found Encoding: ${encoding}"
iconv -f "${encoding}" -t "utf-8" ${line} -o ${line}.tmp
mv ${line}.tmp ${line}
done
file -i file_name
を使用して、元のファイル形式を正確に確認できます。
それを取得したら、次のことができます。
iconv -f old_format -t utf-8 input_file -o output_file
誤ってファイルをUTF-7でエンコードしましたが、同様の問題がありました。 file -i name.file
と入力すると、charset=us-ascii
が返されます。 iconv -f us-ascii -t utf-9//translit name.file
は機能しません。UTF-7はus-asciiのサブセットであり、UTF-8も同様です。
これを解決するために、次を入力しました:iconv -f UTF-7 -t UTF-8//TRANSLIT name.file -o output.file
ここで他の人が提案したもの以外のエンコーディングを決定する方法がわかりません。