【问题标题】:How to convert malformed database characters (ascii to utf-8)如何转换格式错误的数据库字符(ascii 到 utf-8)
【发布时间】:2020-08-16 07:37:00
【问题描述】:

我知道很多人会说这个问题已经得到了这样的回答https://stackoverflow.com/a/4983999/1833322 但是让我解释一下为什么它不是那么直截了当..

我想用 PHP 将“看起来像 ascii”的东西转换成“utf-8”

有一个网站可以做到这一点https://onlineutf8tools.com/convert-ascii-to-utf8

当我输入此字符串 Z…Z 时,我会返回 Z⬦Z,这是正确的输出。

我尝试了iconv 和一些mb_ 功能。虽然我不知道这些功能是否能够做我想要的或我需要的选项。如果无法使用这些功能,我们将不胜感激一些自写的 PHP 代码。 (该网站运行 javascript,我认为 PHP 在这方面的能力并不差)

明确一点:目标是在 PHP 中重新创建该网站正在执行的操作。不要对 ascii 和 utf-8 进行语义辩论

编辑:the website 使用 https://github.com/mathiasbynens/utf8.js 表示

它可以根据编码标准对任何标量 Unicode 代码点值进行编码/解码。

标准链接到https://encoding.spec.whatwg.org/#utf-8 所以这个库说它实现了标准,那么 PHP 呢?

【问题讨论】:

    标签: php character-encoding non-ascii-characters


    【解决方案1】:

    UTF-8 是 ASCII 的超集,因此从 ASCII 转换为 UTF-8 就像将汽车转换为车辆。

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

    您链接的工具似乎使用术语“ASCII”作为mojibake 的同义词(它说“汽车”但意思是“废金属”)。 Mojibake 通常以这种方式发生:

    1. 你选择一个非英文字符:'WHITE MEDIUM DIAMOND' (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 进行操作,但尝试 all 编码 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;不太确定这意味着什么。)

    【讨论】:

    • 有没有一个php函数可以从…转到\xC3\xA2\xC2\xAC\xC2\xA6?这似乎是第一次开始时缺少的一步。否则很好的答案!我会放一点赏金作为奖励。
    • 如果您的编辑器配置为将文件保存为 UTF-8,那么这两个字符串之间根本没有区别。如果您需要 bin2hex 的字节,或者只使用 Unicode Inspector
    • 我用两个十六进制编辑器(bless 和 wxHexEditor)尝试了这个,并检查了一个内容为 … 的文件。两位编辑都显示C3 A2 E2 82 AC C2 A6
    • …(来自wchar)是正确的。我的例子是⬦(来自Windows-1252)。
    猜你喜欢
    • 2021-12-31
    • 2013-04-19
    • 2011-06-19
    • 2016-11-13
    • 2010-10-24
    • 1970-01-01
    • 2014-09-08
    • 2011-06-22
    • 1970-01-01
    相关资源
    最近更新 更多