私が作業しているファイルで見つけた奇妙な文字を識別しようとしています:
$ cat file
�
$ od file
0000000 005353
0000002
$ od -c file
0000000 353 \n
0000002
$ od -x file
0000000 0aeb
0000002
ファイルはISO-8859エンコーディングを使用しており、UTF-8に変換できません。
$ iconv -f ISO-8859 -t UTF-8 file
iconv: conversion from `ISO-8859' is not supported
Try `iconv --help' or `iconv --usage' for more information.
$ iconv -t UTF-8 file
iconv: illegal input sequence at position 0
$ file file
file: ISO-8859 text
私の主な質問は、ここでod
の出力をどのように解釈できるかです。私は このページ を使用しようとしています。これにより、異なる文字表現間で翻訳できますが、005353
"16進コードポイント"は卓
正しくないようで、0aeb
"16進コードポイント"は૫
これもまた間違っているようです。
では、3つのオプション(355
、005353
または0aeb
)彼らが表現することになっているキャラクターを見つけるには?
はい、私はUnicodeツールを試しましたが、それも有効なUTF文字ではないようです。
$ uniprops $(cat file)
U+FFFD ‹�› \N{REPLACEMENT CHARACTER}
\pS \p{So}
All Any Assigned Common Zyyy So S Gr_Base Grapheme_Base Graph X_POSIX_Graph
GrBase Other_Symbol Print X_POSIX_Print Symbol Specials Unicode
unicode U + FFFD文字の説明を理解すると、それは実際の文字ではなく、破損した文字のプレースホルダーになります。ファイルは実際にはUTF-8でエンコードされていないため、これは理にかなっています。
ファイルには2バイト、EBと0Aが16進数で含まれています。ファイルが ISO-8859-1 ;のような、文字ごとに1バイトの文字セットを使用している可能性があります。その文字セットでは、EBはëです。
$ printf "\353\n" | iconv -f ISO-8859-1
ë
他の候補は、δ- コードページ437 、Ù- コードページ85 ...
od -x
の出力は、エンディアンのため、この場合は混乱します。より良いオプションはシングルバイトを使用する-t x1
です:
$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002
od -x
は、一度に2バイトを読み取るod -t x2
にマップし、リトルエンディアンシステムでは、バイトを逆の順序で出力します。
このような、UTF-8として有効ではない(またはUTF-8ファイルとして解釈されても意味がない)ファイルに遭遇した場合、そのエンコーディング(および文字セット)を自動的に決定する確実な方法はありません。コンテキストが役立ちます。それが過去20年間にWestern PCで作成されたファイルである場合、ISO-8859-1、-15(ユーロバリアント)、またはWindows-1252でエンコードされている可能性がかなりあります。それより古い場合は、CP-437とCP-850が候補になる可能性があります。東ヨーロッパのシステム、ロシアのシステム、アジアのシステムのファイルは、私がよく知らないさまざまな文字セットを使用します。次に、EBCDICがあります... iconv -l
は、iconv
が認識しているすべての文字セットをリストし、そこから試行錯誤することができます。
(ある時点で、私はCP-437とATASCIIのほとんどを暗記していました。それらは当時のことでした。)
od
はoctal dumpの省略形なので、005353
は2バイトの8進数のワード、od -x
は0aeb
はWordの16進数で、実際のファイルの内容は2バイトですeb
および0a
16進数で、この順序で。
だから両方005353
および0aeb
を単に「16進コードポイント」として解釈することはできません。
0a
は改行(LF)であり、eb
はエンコーディングによって異なります。 file
はエンコーディングを推測しているだけなので、何でもかまいません。ファイルがどこから来たのかなどの詳細情報がなければ、見つけるのは難しいでしょう。
テキストファイルの文字セットを100%正確に推測することは不可能です。
chardet、firefox、file -iなどのツールは、明示的な文字セット情報が定義されていない場合(HTMLにメタ文字セット=が含まれる場合など)。 ..頭の中で、物事は簡単です)テキストが十分に大きい場合、それほど悪くない発見的手法を使用しようとします。
以下では、chardet
(pip install chardet
/apt-get install python-chardet
必要であれば)。
$ echo "in Noël" | iconv -f utf8 -t latin1 | chardet
<stdin>: windows-1252 with confidence 0.73
適切な文字セット候補が得られたら、iconv
、recode
などを使用して、ファイルの文字セットを「アクティブ」な文字セット(私の場合はutf-8)に変更し、正しく推測されたかどうかを確認します。 ..
iconv -f windows-1252 -t utf-8 file
一部の文字セット(iso-8859-3、iso-8859-1など)には、多くの共通の文字があります-完全な文字セットを見つけたかどうかを確認するのは簡単ではありません...
したがって、メタデータを関連するテキスト(XMLなど)に関連付けることが非常に重要です。
#!/bin/bash
#
# Search in a file, a known (part of a ) String (i.E.: Begrüßung),
# by testing all encodings
#
[[ $# -ne 2 ]] && echo "Usage: encoding-Finder.sh FILE fUnKy_CHAR_FOR_SURE_IN_FILE" && exit
FILE=$1
PATTERN=$2
for enc in $( iconv -l | sed 's/..$//')
do
iconv -f $enc -t UTF-8 $FILE 2>/dev/null | grep -m 1 $PATTERN && echo $enc
done
たとえば、Begrungという単語が含まれているファイルを取得した場合、Begrüßungが意図されていると推測できます。だから私はそれをすべての既知のencodindgsで変換し、見つかるかどうかを調べます。
通常、適合するように見える複数のエンコーディングがあります。
長いファイルの場合は、数百ページを変換する代わりにスニペットをカットする場合があります。
だから私はそれを呼びます
encodingfinder.sh FILE Begrüßung
また、スクリプトテストでは、既知のエンコーディングで変換するかどうかに関係なく、「Begrüßung」を生成します。
ファンキーなキャラクターが目立つ場合が多いため、このようなキャラクターを見つけるには、通常はあまり役に立ちません。通常、文脈から、検索する適切な単語を推測できます。しかし、これをhexeditorで確認し、これが何バイトであるかを確認したくないので、エンコーディングの無限のテーブルにアクセスして、攻撃者を見つけます。 :)