Лучший способ исправить искаженные данные, вызванные ложным кодированием - PullRequest
4 голосов
/ 09 марта 2010

У меня есть набор данных, который содержит искаженные текстовые поля из-за ошибок кодирования при многих операциях импорта / экспорта из одной базы данных в другую. Большинство ошибок были вызваны преобразованием UTF-8 в ISO-8859-1. Как ни странно, ошибки не согласованы: слово ' München ' появляется как ' München ' в некотором месте, а также как ' Менхен 'где-то еще.

Есть ли хитрость в SQL-сервере для исправления подобного дерьма? Первое, что я могу придумать, это использовать предложение COLLATE, чтобы Ã интерпретировалось как ü , но я точно не знаю, как. Если это невозможно сделать на уровне БД, знаете ли вы какой-либо инструмент, который помогает для массовой коррекции? (нет ручного инструмента поиска / замены, но есть инструмент, который каким-то образом угадывает искаженный текст и исправляет его)

Ответы [ 4 ]

4 голосов
/ 14 марта 2010

Я был в точно в той же позиции. Рабочий сервер MySQL был настроен на использование латиницы 1, старые данные - латыни 1, новые данные - utf8, но сохранялись в столбцах latin1, затем добавлялись столбцы utf8 ... Каждая строка могла содержать любое количество кодировок.

Большая проблема в том, что не существует единого решения, которое бы исправляло все, потому что многие устаревшие кодировки используют одни и те же байты для разных символов. Это означает, что вам придется прибегнуть к эвристике. В моем классе Utf8Voodoo имеется огромный массив байтов от 127 до 255, т.е. устаревшая однобайтовая кодировка не-ASCII символов.

// ISO-8859-15 has the Euro sign, but ISO-8859-1 has also been used on the
// site. Sigh. Windows-1252 has the Euro sign at 0x80 (and other printable
// characters in 0x80-0x9F), but mb_detect_encoding never returns that
// encoding when ISO-8859-* is in the detect list, so we cannot use it.
// CP850 has accented letters and currency symbols in 0x80-0x9F. It occurs
// just a few times, but enough to make it pretty much impossible to
// automagically detect exactly which non-ISO encoding was used. Hence the
// need for "likely bytes" in addition to the "magic bytes" below.

/**
 * This array contains the magic bytes that determine possible encodings.
 * It works by elimination: the most specific byte patterns (the array's
 * keys) are listed first. When a match is found, the possible encodings
 * are that entry's value.
 */
public static $legacyEncodingsMagicBytes = array(
    '/[\x81\x8D\x8F\x90\x9D]/' => array('CP850'),
    '/[\x80\x82-\x8C\x8E\x91-\x9C\x9E\x9F]/' => array('Windows-1252', 'CP850'),
    '/./' => array('ISO-8859-15', 'ISO-8859-1', 'Windows-1252', 'CP850'),
);

/**
 * This array contains the bytes that make it more likely for a string to
 * be a certain encoding. The keys are the pattern, the values are arrays
 * with (encoding => likeliness score modifier).
 */
public static $legacyEncodingsLikelyBytes = array(
    // Byte | ISO-1  | ISO-15 | W-1252 | CP850
    // 0x80 | -      | -      | €      | Ç
    '/\x80/' => array(
        'Windows-1252' => +10,
    ),
    // Byte | ISO-1  | ISO-15 | W-1252 | CP850
    // 0x93 | -      | -      | “      | ô
    // 0x94 | -      | -      | ”      | ö
    // 0x95 | -      | -      | •      | ò
    // 0x96 | -      | -      | –      | û
    // 0x97 | -      | -      | —      | ù
    // 0x99 | -      | -      | ™      | Ö
    '/[\x93-\x97\x99]/' => array(
        'Windows-1252' => +1,
    ),
    // Byte | ISO-1  | ISO-15 | W-1252 | CP850
    // 0x86 | -      | -      | †      | å
    // 0x87 | -      | -      | ‡      | ç
    // 0x89 | -      | -      | ‰      | ë
    // 0x8A | -      | -      | Š      | è
    // 0x8C | -      | -      | Œ      | î
    // 0x8E | -      | -      | Ž      | Ä
    // 0x9A | -      | -      | š      | Ü
    // 0x9C | -      | -      | œ      | £
    // 0x9E | -      | -      | ž      | ×
    '/[\x86\x87\x89\x8A\x8C\x8E\x9A\x9C\x9E]/' => array(
        'Windows-1252' => -1,
    ),
    // Byte | ISO-1  | ISO-15 | W-1252 | CP850
    // 0xA4 | ¤      | €      | ¤      | ñ
    '/\xA4/' => array(
        'ISO-8859-15' => +10,
    ),
    // Byte | ISO-1  | ISO-15 | W-1252 | CP850
    // 0xA6 | ¦      | Š      | ¦      | ª
    // 0xBD | ½      | œ      | ½      | ¢
    '/[\xA6\xBD]/' => array(
        'ISO-8859-15' => -1,
    ),
    // Byte | ISO-1  | ISO-15 | W-1252 | CP850
    // 0x82 | -      | -      | ‚      | é
    // 0xA7 | §      | §      | §      | º
    // 0xFD | ý      | ý      | ý      | ²
    '/[\x82\xA7\xCF\xFD]/' => array(
        'CP850' => +1
    ),
    // Byte | ISO-1  | ISO-15 | W-1252 | CP850
    // 0x91 | -      | -      | ‘      | æ
    // 0x92 | -      | -      | ’      | Æ
    // 0xB0 | °      | °      | °      | ░
    // 0xB1 | ±      | ±      | ±      | ▒
    // 0xB2 | ²      | ²      | ²      | ▓
    // 0xB3 | ³      | ³      | ³      | │
    // 0xB9 | ¹      | ¹      | ¹      | ╣
    // 0xBA | º      | º      | º      | ║
    // 0xBB | »      | »      | »      | ╗
    // 0xBC | ¼      | Œ      | ¼      | ╝
    // 0xC1 | Á      | Á      | Á      | ┴
    // 0xC2 | Â      | Â      | Â      | ┬
    // 0xC3 | Ã      | Ã      | Ã      | ├
    // 0xC4 | Ä      | Ä      | Ä      | ─
    // 0xC5 | Å      | Å      | Å      | ┼
    // 0xC8 | È      | È      | È      | ╚
    // 0xC9 | É      | É      | É      | ╔
    // 0xCA | Ê      | Ê      | Ê      | ╩
    // 0xCB | Ë      | Ë      | Ë      | ╦
    // 0xCC | Ì      | Ì      | Ì      | ╠
    // 0xCD | Í      | Í      | Í      | ═
    // 0xCE | Î      | Î      | Î      | ╬
    // 0xD9 | Ù      | Ù      | Ù      | ┘
    // 0xDA | Ú      | Ú      | Ú      | ┌
    // 0xDB | Û      | Û      | Û      | █
    // 0xDC | Ü      | Ü      | Ü      | ▄
    // 0xDF | ß      | ß      | ß      | ▀
    // 0xE7 | ç      | ç      | ç      | þ
    // 0xE8 | è      | è      | è      | Þ
    '/[\x91\x92\xB0-\xB3\xB9-\xBC\xC1-\xC5\xC8-\xCE\xD9-\xDC\xDF\xE7\xE8]/' => array(
        'CP850' => -1
    ),
/* etc. */

Затем вы перебираете байты (не символы) в строках и сохраняете результаты. Дайте мне знать, если вам нужна дополнительная информация.

1 голос
/ 09 марта 2010

Скачать iconv - вы можете получить двоичные файлы для Win32, а также Unix / Linux. Это инструмент командной строки, который берет исходный файл и после указания входных и выходных кодировок выполнит необходимое преобразование для вас в STDOUT.

Я часто использую это для преобразования из UTF-16 (как вывод из файлов экспорта SQL Server 2005) в ASCII.

Вы можете скачать здесь: http://gnuwin32.sourceforge.net/packages/libiconv.htm

0 голосов
/ 08 сентября 2015

Взгляните на https://github.com/LuminosoInsight/python-ftfy - это неплохо для эвристической коррекции, которая позаботится о вполне еще большем уродстве, чем вы ожидаете, когда посмотрите на небольшие выборки ваших данных .

0 голосов
/ 10 марта 2010

Учитывая сложность данных (несколько кодировок в одной строке / записи). Я думаю, вам придется экспортировать / вывести данные, а затем запустить обработку для этого.

Я думаю, что лучшим способом будет последовательность ручных замен. Может быть, какой-то код исправления орфографии может найти все ошибки - тогда вы можете добавить явный код исправления. Затем повторять, пока проверка орфографии не перестанет находить ошибки?

(Очевидно, добавьте правильные слова в словарь для проверки орфографии).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...