我知道很多人都会说,这个问题已经有人回答过了,比如说 https:/stackoverflow.coma49839991833322。 但是,让我解释一下为什么它不是那么直接。
我想用PHP把一些 "看起来像ascii "的东西转换成 "utf-8"。
有一个网站可以做到这一点 https:/onlineutf8tools.comconvert-ascii-to-utf8。
当我输入这个字符串时 Z…Z
我回来 Z⬦Z
这是正确的输出。
我试过 iconv
和一些 mb_
的功能,但我不知道这些功能是否能够做到我想要的,或者说我需要哪些选项。虽然我不知道这些函数是否能够做到我想要的,或者我需要哪些选项。如果这些函数不能实现的话,希望能得到一些自写的PHP代码。(网站运行的是javascript,我不认为PHP我在这方面的能力较差)
要说明的是:我们的目标是在 PHP 中重新创建那个网站正在做的事情。而不是为了争论ascii和utf-8的语义。
编辑 该网站 用途 https:/github.commathiasbynensutf8.js。 其中说
根据编码标准,它可以对任何标量Unicode码点值进行编码。
标准链接到 https:/encoding.spec.whatwg.org#utf-8 所以这个库说它实现了标准,那么PHP呢 ?
UTF-8 是 ASCII 的超集,所以将 ASCII 转换为 UTF-8 就像将汽车转换为汽车一样。
+--- UTF-8 ---------------+
| |
| +--- ASCII ---+ |
| | | |
| +-------------+ |
+-------------------------+
你链接的工具似乎使用 "ASCII "作为同义词。潮州烤肉 说是 "汽车",但意思是 "废旧金属")。Mojibake通常是这样发生的。
你选择一个非英语的字符。⬦
"WHITE MEDIUM DIAMOND" (U+2B26)
你使用UTF-8进行编码。0xE2 0xAC 0xA6
你在一个配置为使用你所在地区广泛使用的单字节编码的工具中打开数据流。Windows-1252
你在单字节编码的字符表中查找UTF-8字符的各个字节。
0xE2
-> â
0xAC
-> -> ¬
0xA6
->。¦
你将得到的字符用UTF-8编码。
â
= 'LATIN SMALL LETTER A WITH CIRCUMFLEX' (U+00E2) = 0xC3 0xA2
¬
= NOT SIGN' (U+00AC) = 0xC2 0xAC
¦
= 'BROKEN BAR'(U+00A6) = 0xC2 0xA6
因此,你已经将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"
但如果你不知道的话,就很棘手了。我想你可以这样做。
编一个字典,里面有不同的单字节编码的字节序列 然后用某种贝叶斯推理法找出最可能的编码方式 (我真的不能帮你这个忙。)
试试最有可能的编码,然后目测一下输出以确定哪个是正确的。
// 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;
}
如果(就像你的情况)你知道原文是什么 而且你很确定你没有混合编码,就像#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
(不知道是什么意思。)