web-dev-qa-db-ja.com

条件付きでUTF-8に再コーディングするにはどうすればよいですか?

さまざまなコンピューターで時間の経過とともに収集された大量のテキストファイルのエンコードを統合しています。私は主に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スクリプトの条件付きで結果を使用できる限り、他のツールでも問題ありません...

4
Jonik

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であることに完全に依存します。そして、これは明らかに私が持っているファイルの種類に適した非常に限られた解決策なので、問題を解決するより良い答えを自由に追加してくださいより一般的な方法。

3
Jonik

このメッセージはかなり古いですが、私はこの問題に貢献できると思います:
最初に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 {} \;

これがお役に立てば幸いです。

7
Pierre FABIER

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であった場合、出力は入力と同じになります。

2
user46971

私は少し遅れていますが、同じ質問に何度も何度も苦労しています...それを行うための素晴らしい方法を見つけたので、それを共有せずにはいられません:)

Emacsユーザーになりましたが、今日はvimを使用することをお勧めします。

この簡単なコマンドを使用すると、中身が目的のエンコーディングに関係なく、ファイルが再コーディングされます。

vim +'set nobomb | set fenc=utf8 | x' <filename>

これより良い結果をもたらすものは見つかりませんでした。

それが他の人の助けになることを願っています。

1
user2380653

ISO-8859-1とUTF-8はどちらも最初の128文字で同一であるため、問題は実際には、128を超えるように数値的にエンコードされた、面白い文字を含むファイルを検出する方法です。

面白い文字の数が多すぎない場合は、egrepを使用してスキャンし、再コーディングが必要なファイルを見つけることができます。

1
harrymc

文字セットを検出する方法はたくさんありますが、100%信頼できるものはありません。可能な言語と文字セットが制限されていて、特定のバイトを数えるのに十分なテキストがある場合、これは非常に役立ちます。

もう1つのアプローチは、recoderecode を使用)を試行し、終了値にエラーがないかどうかを確認することです。

ラテン文字を使用する言語で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
0
mivk

を使用して、ファイルの文字セットを検出および推測できます。

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*
0
Phlogi