web-dev-qa-db-ja.com

壊れたUTF-8エンコーディングの修正

私はいくつかの悪いUTF-8エンコーディングを修正する過程にあります。現在、PHP 5とMySQLを使用しています。

私のデータベースには、次のように表示されるエンコードが正しくないインスタンスがいくつかあります。

  • データベース照合はutf8_general_ciです
  • PHPは適切なUTF-8ヘッダーを使用しています
  • Notepad ++は、BOMなしでUTF-8を使用するように設定されています
  • データベース管理は phpMyAdmin で処理されます
  • アクセント付き文字のすべてのケースが壊れているわけではありません

î、í、üなどのインスタンスを適切なアクセント付きUTF-8文字にマッピングするのに役立つ何らかの機能が必要です。

58
Jayrox

私は過去に多くのUTF8の壊れた状況を「修正」しなければなりませんでしたが、残念ながらそれは決して簡単ではなく、しばしば不可能です。

どのように破損したかを正確に判断できず、常にまったく同じ方法で破損した場合を除き、損傷を「元に戻す」ことは困難になります。

損傷を取り消そうとする場合、最善の方法は、いくつかのサンプルコードの記述を開始することです。ここでは、mb_convert_encoding()の呼び出しで多数のバリエーションを試し、「from」と「to」の組み合わせを見つけることができるかどうかを確認しますデータを修正します。結局、苦痛のレベルが関係しているために古いデータの修正を気にすることさえせずに、代わりに物事を修正することが最善です。

ただし、これを行う前に、この問題の原因となっているすべてのものを最初に修正する必要があります。 DBテーブルの照合とエディターが適切に設定されていることは既に述べました。しかし、すべてが適切にUTF-8であることを確認するためにチェックする必要がある場所が他にもあります。

  • HTMLをUTF-8として提供していることを確認してください:
    • header( "Content-Type:text/html; charset = utf-8");
  • PHPデフォルト文字セットをutf-8:に変更します]
    • ini_set( "default_charset"、 'utf-8');
  • データベースが常にutf-8で通信しない場合は、接続ごとに通知してutf-8モードになっていることを確認する必要がある場合があります。MySQLでは、次のコマンドを発行して行います。
    • 文字セットutf8
  • あなたはウェブサーバーに常にUTF8で話そうとするように指示する必要があるかもしれません、Apacheではこのコマンドは次のとおりです:
    • AddDefaultCharset UTF-8
  • 最後に、常にPHP UTF-8に適切に対応している関数を使用していることを確認する必要があります。これは常に mb _ * スタイルの 'マルチバイト対応'を使用することを意味します文字列関数。htmlspecialchars()などの関数を呼び出すときに、適切な 'utf-8'文字セットパラメーターを最後に含めて、正しくエンコードされないようにすることも意味します。

プロセス全体のいずれかのステップを逃した場合、エンコードが破損し、問題が発生する可能性があります。ただし、utf-8を実行する「溝」に入ると、これはすべて第二の性質になります。そしてもちろん、PHP6はgetgoからの完全なUnicodeの不満であると想定されており、これにより多くのことが簡単になります(うまくいけば)

62
Eli

二重エンコードされたUTF8文字(さまざまなスマートクォート、ダッシュ、アポストロフィ、クォーテーションマークなど)がある場合、mysqlでデータをダンプし、それを読み戻して壊れたエンコードを修正します。

このような:

mysqldump -h DB_Host -u DB_USER -p DB_PASSWORD --opt --quote-names \
    --skip-set-charset --default-character-set=latin1 DB_NAME > DB_NAME-dump.sql

mysql -h DB_Host -u DB_USER -p DB_PASSWORD \
    --default-character-set=utf8 DB_NAME < DB_NAME-dump.sql

これは、ダブルエンコードされたUTF-8に対する100%の修正でした。

ソース: http://blog.hno3.org/2010/04/22/fixing-double-encoded-utf-8-data-in-mysql/

92
jsdalton

すでにUTF-8である文字列に対してutf8_encode()を使用すると、複数回エンコードされたときに文字化けします。

文字列をUTF-8に変換する関数toUTF8()を作成しました。

文字列のエンコーディングを指定する必要はありません。 Latin1(iso 8859-1)、Windows-1252、UTF8、またはこれら3つの組み合わせを使用できます。

同じ文字列にエンコードが混在するフィードでこれを自分で使用しました。

使用法:

_$utf8_string = Encoding::toUTF8($mixed_string);

$latin1_string = Encoding::toLatin1($mixed_string);
_

私の他の関数fixUTF8()は、UTF8に複数回エンコードされた場合、文字化けしたUTF8文字列を修正します。

使用法:

_$utf8_string = Encoding::fixUTF8($garbled_utf8_string);
_

例:

_echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
_

出力されます:

_Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
_

ダウンロード:

https://github.com/neitanod/forceutf8

78

エンコードが壊れているxmlファイルに問題があり、utf-8であると言っていましたが、utf-8ではない文字がありました。
mb_convert_encoding()で何度か試行錯誤を繰り返した後、

mb_convert_encoding($text, 'Windows-1252', 'UTF-8')
11
Celleb

Danが指摘したように、それらをバイナリに変換してから、エンコードを変換/修正する必要があります。

たとえば、latin1として保存されたutf8の場合、次のSQLで修正されます。

UPDATE table
   SET field = CONVERT( CAST(field AS BINARY) USING utf8)
 WHERE $broken_field_condition
10
blueyed

これはあまりエレガントではないことは知っていますが、文字列が二重にエンコードされている可能性があると述べた後、この関数を作成しました:

function fix_double encoding($string)
{
    $utf8_chars = explode(' ', 'À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö');
    $utf8_double_encoded = array();
    foreach($utf8_chars as $utf8_char)
    {
            $utf8_double_encoded[] = utf8_encode(utf8_encode($utf8_char));
    }
    $string = str_replace($utf8_double_encoded, $utf8_chars, $string);
    return $string;
}

これは、私が経験している二重エンコードを削除するのに完全に機能するようです。他の人にとっては問題になる可能性のあるキャラクターのいくつかが欠けているのでしょう。しかし、私のニーズには完全に機能しています。

2
Jayrox

方法は、バイナリに変換してからエンコードを修正することです

2
Dan

確認すべきもう1つのことは、たまたま私の解決策でした( here が見つかりました)。サーバーからデータがどのように返されるかです。私のアプリケーションでは、PDOを使用してPHP=からMySQLに接続します。UTF-8形式でデータを取得するというフラグを接続に追加する必要がありました。

答えは

$dbHandle = new PDO("mysql:Host=$dbHost;dbname=$dbName;charset=utf8", $dbUser, $dbPass, 
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
1
Luke Madhanga

私はずっと前に同じ問題を抱えていましたが、それを使用して修正しました

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15">
0
Jose De Gouveia

Utf-8は、ある時点でiso8859-1またはWin-1250として解釈されているようです。

「私のデータベースでは、いくつかの不適切なエンコーディングのインスタンスがあります」と言うとき、これをどのように確認しましたか?アプリ、phpmyadmin、またはコマンドラインクライアントから? all utf-8エンコーディングはこのように表示されますか、それとも一部のみ表示されますか?エンコードが間違っていて、すでにutf-8であったときにiso8859-1からutf-8に誤って変換された可能性はありますか?

0
teambob

数日間の検索で解決策を見つけました。私のコメントは埋葬されますが、とにかく...

  1. 破損したデータをphpで取得します。

  2. セット名UTF8を使用しません

  3. データでutf8_decode()を使用します

  4. UTF8のセット名を使用せずに、新しいデコードされたデータでデータベースを更新します

そしてボイラ:)

0

このスクリプトにはすてきなアプローチがありました。選択した言語に変換するのはそれほど難しくないはずです。

http://plasmasturm.org/log/416/

#!/usr/bin/Perl
use strict;
use warnings;

use Encode qw( decode FB_QUIET );

binmode STDIN, ':bytes';
binmode STDOUT, ':encoding(UTF-8)';

my $out;

while ( <> ) {
  $out = '';
  while ( length ) {
    # consume input string up to the first UTF-8 decode error
    $out .= decode( "utf-8", $_, FB_QUIET );
    # consume one character; all octets are valid Latin-1
    $out .= decode( "iso-8859-1", substr( $_, 0, 1 ), FB_QUIET ) if length;
  }
  print $out;
}
0
Erik Aronesty