Khi tôi gặp sự cố như thế này, tôi đã sử dụng tập lệnh Perl để đảm bảo rằng dữ liệu được chuyển đổi thành UTF-8 hợp lệ bằng cách sử dụng mã như sau:
use Encode;
binmode(STDOUT, ":utf8");
while (<>) {
print Encode::decode('UTF-8', $_);
}
Tập lệnh này có (có thể bị hỏng) UTF-8 trên stdin
và in lại UTF-8 hợp lệ thành stdout
. Các ký tự không hợp lệ được thay thế bằng �
(U+FFFD
, ký tự thay thế Unicode
).
Nếu bạn chạy tập lệnh này trên đầu vào UTF-8 tốt, đầu ra phải giống với đầu vào.
Nếu bạn có dữ liệu trong cơ sở dữ liệu, bạn nên sử dụng DBI để quét (các) bảng của bạn và lọc tất cả dữ liệu bằng cách sử dụng phương pháp này để đảm bảo rằng mọi thứ đều hợp lệ UTF-8.
Đây là phiên bản Perl one-liner của cùng một tập lệnh này:
perl -MEncode -e "binmode STDOUT,':utf8';while(<>){print Encode::decode 'UTF-8',\$_}" < bad.txt > good.txt
CHỈNH SỬA:Đã thêm giải pháp chỉ dành cho Java .
Đây là một ví dụ về cách thực hiện việc này trong 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: Пр?вет
}
}