Как преобразовать неправильно сформированные символы базы данных (ascii в utf-8) - PullRequest
0 голосов
/ 01 мая 2020

Я знаю, что многие скажут, что на этот вопрос уже был получен ответ: { ссылка } Но позвольте мне объяснить, почему это не так просто, как отправлено ..

Я хотел бы использовать PHP для преобразования чего-то "похожего на ascii" в "utf-8"

Есть веб-сайт, который делает это https://onlineutf8tools.com/convert-ascii-to-utf8

Когда я ввожу эту строку Z…Z я получаю обратно Z⬦Z, что является правильным выводом.

Я попробовал iconv и некоторые mb_ функции. Хотя я не могу понять, способны ли эти функции делать то, что я хочу, или какие опции мне нужны. Если это невозможно с этими функциями, будет полезен некоторый самописный код PHP. (Веб-сайт работает javascript, и я не думаю, что PHP я менее способен в этом отношении)

Чтобы было ясно: цель состоит в том, чтобы воссоздать в PHP то, что делает этот веб-сайт. Не иметь семанти c дебатов об ascii и utf-8

РЕДАКТИРОВАТЬ: веб-сайт использует https://github.com/mathiasbynens/utf8.js, который говорит

он может кодировать / декодировать любые скалярные значения кодовой точки Unicode в соответствии со стандартом кодирования.

Стандартное связывание с https://encoding.spec.whatwg.org/#utf -8 Так что эта библиотека говорит, что она реализует стандарт, тогда как насчет PHP?

1 Ответ

1 голос
/ 02 мая 2020

UTF-8 - это расширенный набор ASCII, поэтому преобразование из ASCII в UTF-8 похоже на преобразование автомобиля в транспортное средство.

+--- UTF-8 ---------------+
|                         |
|   +--- ASCII ---+       |
|   |             |       |
|   +-------------+       |
+-------------------------+

Инструмент, на который вы ссылаетесь, использует термин "ASCII" в качестве синонима для mojibake (он говорит «машина», но означает «металлолом»). Моджибаке обычно происходит следующим образом:

  1. Вы выбираете не-английский sh символ: 'БЕЛЫЙ СРЕДНИЙ АЛМАЗ' (U + 2B26)

  2. Вы кодируете его, используя UTF-8: 0xE2 0xAC 0xA6

  3. Вы открываете поток в инструменте, настроенном для использования однобайтовой кодировки, которая является широко используется в вашем регионе: Windows -1252

  4. Вы просматриваете отдельные байты символа UTF-8 в таблице символов однобайтовых кодировка:

    • 0xE2 -> â
    • 0xAC -> ¬
    • 0xA6 -> ¦
  5. Вы кодируете результирующие символы в UTF-8:

Таким образом вы преобразовали поток UTF-8 0xE2 0xAC 0xA6 ( в) так что поток UTF-8 0xC3 0xA2 0xC2 0xAC 0xC2 0xA6 (⬦).

Чтобы отменить это, нужно выполнить шаги в обратном порядке. Это просто, если вы знаете, какую прокси-кодировку использовали (Windows -1252 в моем примере):

$mojibake = "\xC3\xA2\xC2\xAC\xC2\xA6";
$proxy = 'Windows-1252';
var_dump($mojibake, bin2hex($mojibake));
$original = mb_convert_encoding($mojibake, $proxy, 'UTF-8');
var_dump($original, bin2hex($original));
string(6) "⬦"
string(12) "c3a2c2acc2a6"
string(3) "⬦"
string(6) "e2aca6"

Но это сложно, если вы этого не сделаете. Я думаю, вы можете:

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

  2. Попробуйте наиболее вероятные кодировки и визуально проверьте вывод, чтобы определить, что является правильным:

    // Source code saved as UTF-8
    $mojibake = "Z…Z";
    foreach (mb_list_encodings() as $proxy) {
        $original = mb_convert_encoding($mojibake, $proxy, 'UTF-8');
        echo $proxy, ': ', $original, PHP_EOL;
    }
    
  3. Если (как в вашем случае) вы знаете, что такое исходный текст, и уверены, что у вас нет смешанных кодировок, сделайте как # 2, но попытайтесь все кодировки PHP поддерживает:

    // Source code saved as UTF-8
    $mojibake = 'Z…Z';
    $expected = 'Z⬦Z';
    foreach (mb_list_encodings() as $proxy) {
        $current = @mb_convert_encoding($mojibake, $proxy, 'UTF-8');
        if ($current === $expected) {
            echo "$proxy: match\n";
        }
    }
    

    (Это печатает wchar: match; не совсем уверен, что это значит.)

...