web-dev-qa-db-ja.com

MySQLのutf8エンコーディングに適さない不良文字を削除するにはどうすればよいですか?

ダーティデータがあります。 this のような文字が含まれている場合があります。このデータを使用して、次のようなクエリを作成します

WHERE a.address IN ('mydatahere')

このキャラクターには

org.hibernate.exception.GenericJDBCException:照合の不正な組み合わせ(utf8_bin、IMPLICIT)、(utf8mb4_general_ci、COERCIBLE)、(utf8mb4_general_ci、COERCIBLE)for operation 'IN'

このような文字を除外するにはどうすればよいですか?私はJavaを使用しています。

ありがとう。

16

このような問題が発生したときは、Perlスクリプトを使用して、次のようなコードを使用してデータが有効なUTF-8に変換されるようにしました。

use Encode;
binmode(STDOUT, ":utf8");
while (<>) {
    print Encode::decode('UTF-8', $_);
}

このスクリプトは、stdinで(おそらく破損している)UTF-8を受け取り、有効なUTF-8をstdoutに再出力します。無効な文字はU+FFFDnicode置換文字 )に置き換えられます。

このスクリプトを適切なUTF-8入力で実行すると、出力は入力と同じになります。

データベースにデータがある場合、DBIを使用してテーブルをスキャンし、このアプローチを使用してすべてのデータをスクラブして、すべてが有効なUTF-8であることを確認することは理にかなっています。

これは、同じスクリプトのPerlワンライナーバージョンです。

Perl -MEncode -e "binmode STDOUT,':utf8';while(<>){print Encode::decode 'UTF-8',\$_}" < bad.txt > good.txt

編集:Javaのみのソリューションを追加しました

これは、Javaでこれを行う方法の例です。

import Java.nio.ByteBuffer;
import Java.nio.CharBuffer;
import Java.nio.charset.CharacterCodingException;
import Java.nio.charset.Charset;
import Java.nio.charset.CharsetDecoder;
import Java.nio.charset.CodingErrorAction;

public class UtfFix {
    public static void main(String[] args) throws InterruptedException, CharacterCodingException {
        CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
        decoder.onMalformedInput(CodingErrorAction.REPLACE);
        decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
        ByteBuffer bb = ByteBuffer.wrap(new byte[] {
            (byte) 0xD0, (byte) 0x9F, // 'П'
            (byte) 0xD1, (byte) 0x80, // 'р'
            (byte) 0xD0,              // corrupted UTF-8, was 'и'
            (byte) 0xD0, (byte) 0xB2, // 'в'
            (byte) 0xD0, (byte) 0xB5, // 'е'
            (byte) 0xD1, (byte) 0x82  // 'т'
        });
        CharBuffer parsed = decoder.decode(bb);
        System.out.println(parsed);
        // this prints: Пр?вет
    }
}
9
mvp

UTF-8との間でエンコードおよびデコードできます。

String label = "look into my eyes 〠.〠";

Charset charset = Charset.forName("UTF-8");
label = charset.decode(charset.encode(label)).toString();

System.out.println(label);

出力:

look into my eyes ?.?

編集:これはJava 6。

7
Ring

この正規表現を使用して、代理文字をフィルタリングできます。

String str  = "????"; //U+20000, represented by 2 chars in Java (UTF-16 surrogate pair)
str = str.replaceAll( "([\\ud800-\\udbff\\udc00-\\udfff])", "");
System.out.println(str.length()); //0
3
Esailija

Javaマシンでバイト配列を文字列に変換すると、ほとんどのマシンではデフォルトで)UTF-16エンコードされた文字列が得られます。非UTF-8を取り除く適切なソリューション文字は次のコードです:

String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa", "Ok"};
for (int i = 0; i < values.length; i++) {
    System.out.println(values[i].replaceAll(
                    //"[\\\\x00-\\\\x7F]|" + //single-byte sequences   0xxxxxxx - commented because of capitol letters
                    "[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences   110xxxxx 10xxxxxx
                    "[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences   1110xxxx 10xxxxxx * 2
                    "[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
            , ""));
}

または、一部の文字列にutf8以外の文字が含まれているかどうかを検証する場合は、次のようにPattern.matchesを使用します。

String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa", "Ok"};
for (int i = 0; i < values.length; i++) {
    System.out.println(Pattern.matches(
                    ".*(" +
                    //"[\\\\x00-\\\\x7F]|" + //single-byte sequences   0xxxxxxx - commented because of capitol letters
                    "[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences   110xxxxx 10xxxxxx
                    "[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences   1110xxxx 10xxxxxx * 2
                    "[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
                    + ").*"
            , values[i]));
}

Webアプリ全体をUTF8互換にするためには、以下をお読みください。
Java webapps でUTF-8を機能させる方法
バイトエンコーディングと文字列の詳細
パターンを確認できます ここ
PHP here

2
despot

PHP-では、印刷可能なデータのみを許可することでこれに取り組みます。これは、DBのデータのクリーンアップに非常に役立ちます。
ただし、これは前処理であり、そのような贅沢さがない場合もあります。

$str = preg_replace('/[[:^print:]]/', '', $str);
0
Chris Lambrou