さまざまなコンピューターで時間の経過とともに収集された大量のテキストファイルのエンコードを統合しています。私は主にISO-8859-1からUTF-8に移行します。これは1つのファイルをうまく変換します:
recode ISO-8859-1..UTF-8 file.txt
もちろん、すべてのファイルに対して自動バッチ処理を実行したいのですが、ファイルごとに上記を実行するだけで、すでにUTF-8でエンコードされているファイルにエンコーディングが壊れています。 (たとえば、ISO-8859-1で元々使用されていた文字「ä」は、上記の再コード化が2回行われた場合、UTF-8として表示され、次のように表示されます。� -> ä -> ä
)
私の質問は、必要な場合にのみ、つまりターゲットエンコーディング(UTF-8)にまだ含まれていないファイルに対してのみ再コードを実行するスクリプトの種類です。私の場合)?
Recodeのmanページを見ると、このようなことを行う方法がわかりませんでした。つまり、これは、ファイルのエンコーディングを簡単にチェックする方法、または少なくともUTF-8であるかどうかに要約されます。 この回答 は、再コード化で有効なUTF-8ファイルを認識できることを意味しますが、どのようにしたらよいでしょうか。 bashスクリプトの条件付きで結果を使用できる限り、他のツールでも問題ありません...
harrymcのアイデア から適応されたこのスクリプトは、条件付きで1つのファイルを再コード化します(特定のUTF-8でエンコードされたスカンジナビア文字の存在に基づいて)。
$ cat recode-to-utf8.sh
#!/bin/sh
# Recodes specified file to UTF-8, except if it seems to be UTF-8 already
result=`grep -c [åäöÅÄÖ] $1`
if [ "$result" -eq "0" ]
then
echo "Recoding $1 from ISO-8859-1 to UTF-8"
recode ISO-8859-1..UTF-8 $1 # overwrites file
else
echo "$1 was already UTF-8 (probably); skipping it"
fi
(もちろん、バッチ処理ファイルはfor f in *txt; do recode-to-utf8.sh $f; done
などの単純な問題です。)
[〜#〜] nb [〜#〜]:これはスクリプトファイル自体がUTF-8であることに完全に依存します。そして、これは明らかに私が持っているファイルの種類に適した非常に限られた解決策なので、問題を解決するより良い答えを自由に追加してくださいより一般的な方法。
このメッセージはかなり古いですが、私はこの問題に貢献できると思います:
最初にrecodeifneededという名前のスクリプトを作成します:
#!/bin/bash
# Find the current encoding of the file
encoding=$(file -i "$2" | sed "s/.*charset=\(.*\)$/\1/")
if [ ! "$1" == "${encoding}" ]
then
# Encodings differ, we have to encode
echo "recoding from ${encoding} to $1 file : $2"
recode ${encoding}..$1 $2
fi
あなたはそれをこのように使うことができます:
recodeifneeded utf-8 file.txt
したがって、再帰的に実行し、すべての* .txtファイルのエンコーディングを(たとえば)utf-8に変更したい場合:
find . -name "*.txt" -exec recodeifneeded utf-8 {} \;
これがお役に立てば幸いです。
UTF-8には、どのバイトシーケンスが有効であるかについての厳密な規則があります。つまり、データcouldがUTF-8の場合、isと仮定すると、誤検知が発生することはめったにありません。
したがって、次のようなことができます(Pythonで):
def convert_to_utf8(data):
try:
data.decode('UTF-8')
return data # was already UTF-8
except UnicodeError:
return data.decode('ISO-8859-1').encode('UTF-8')
シェルスクリプトでは、iconv
を使用して会話を実行できますが、UTF-8を検出する手段が必要になります。 1つの方法は、ソースと宛先の両方のエンコーディングとしてUTF-8でiconv
を使用することです。ファイルが有効なUTF-8であった場合、出力は入力と同じになります。
私は少し遅れていますが、同じ質問に何度も何度も苦労しています...それを行うための素晴らしい方法を見つけたので、それを共有せずにはいられません:)
Emacsユーザーになりましたが、今日はvimを使用することをお勧めします。
この簡単なコマンドを使用すると、中身が目的のエンコーディングに関係なく、ファイルが再コーディングされます。
vim +'set nobomb | set fenc=utf8 | x' <filename>
これより良い結果をもたらすものは見つかりませんでした。
それが他の人の助けになることを願っています。
ISO-8859-1とUTF-8はどちらも最初の128文字で同一であるため、問題は実際には、128を超えるように数値的にエンコードされた、面白い文字を含むファイルを検出する方法です。
面白い文字の数が多すぎない場合は、egrepを使用してスキャンし、再コーディングが必要なファイルを見つけることができます。
文字セットを検出する方法はたくさんありますが、100%信頼できるものはありません。可能な言語と文字セットが制限されていて、特定のバイトを数えるのに十分なテキストがある場合、これは非常に役立ちます。
もう1つのアプローチは、recode
( recode を使用)を試行し、終了値にエラーがないかどうかを確認することです。
ラテン文字を使用する言語でUTF-8とISO-8859-Xのみを区別するためのトリックのひとつは、最初にUTF-16に再コーディングすることです。 UTF-8で機能するか、ISO-8859-Xでエラーが発生して終了します。
私は時々これをスクリプトで使用します:
# UTF-16 or non-text binary ?
if grep -P -q '[\0-\x08\x0B\x0C\x0E-\x1F]' "$file" ; then
if cat "$file" | recode -s utf16/..utf8 &>/dev/null ; then
echo "utf-16"
else
echo "BINARY?"
fi
exit
fi
# plain ASCII ?
if ! grep -P -q '[\x7F-\xFF]' "$file" ; then
echo "ASCII"
exit
fi
# UTF-8 or Latin1/CP1252 ?
# order of tests is important!
for charset in utf8 latin1 cp1252 ; do
if cat "$file" | recode -s $charset/..utf16 &>/dev/null ; then
found=$charset
if [ "$found" == "latin1" ]; then
# checking if latin1 is really cp1252
if grep -P -q '[\x80-\x9F]' "$file" ; then
found=cp1252
fi
fi
break
fi
done
if [ -n "$found" ]; then
echo "$found"
else
echo "UNKNOWN"
fi
を使用して、ファイルの文字セットを検出および推測できます。
file -bi your_file_with_strange_encoding.txt
このbashoneライナーは、上記のコマンドを再コード化の入力として使用し、複数のファイルをループします。
for f in *.txt; do recode -v "`file -bi ${f} | grep -o 'charset=.*' | cut -f2- -d=`..utf-8" ${f}; done
既存のutf-8の変換について心配する必要はありません。再コード化は、その場合は何もしないほど賢く、メッセージを出力します。
Request: *mere copy*