为了账号安全,请及时绑定邮箱和手机立即绑定

PHP 的 utf8_decode 和 C# 的 Encoding.UTF8.GetString

PHP 的 utf8_decode 和 C# 的 Encoding.UTF8.GetString

PHP
MMTTMM 2023-04-21 13:37:45
我有这个 PHP 代码,它使用 utf8_decode() 在 UTF-8 字符串中转换两个字节数组(一个有 32 个字节,另一个有 70 个字节):$bytes32 = [144, 204, 205, 119, 77, 176, 172, 140, 110, 162, 222, 255, 14, 38, 252, 82, 118, 138, 130, 124, 145, 199, 55, 162, 224, 80, 102, 141, 140, 57, 194, 36];$string32 = implode(array_map("chr", $bytes32));$string32Utf8 = utf8_decode($string32);$bytes70 = [239, 191, 189, 239, 191, 189, 239, 191, 189, 119, 77, 239, 191, 189, 239, 191, 189, 239, 191, 189, 110, 239, 191, 189, 239, 191, 189, 239, 191, 189, 14, 38, 239, 191, 189, 82, 118, 239, 191, 189, 239, 191, 189, 124, 239, 191, 189, 239, 191, 189, 55, 239, 191, 189, 239, 191, 189, 80, 102, 239, 191, 189, 239, 191, 189, 57, 239, 191, 189, 36];$string70 = implode(array_map("chr", $bytes70));$string70Utf8 = utf8_decode($string70);echo '$string32Utf8: ' . $string32Utf8; // echoes ???wM???n??&?Rv??|??7??Pf??9?$echo '$string70Utf8: ' . $string70Utf8; // echoes ???wM???n???&?Rv??|??7??Pf??9?$echo '$string32Utf8 === $string70Utf8: ' . json_encode($string32Utf8 ===  $string70Utf8); // echoes false然后我有这个 C# 代码,它使用 Encoding.UTF8.GetString() 做同样的事情:byte[] bytes32 = new byte[] { 144, 204, 205, 119, 77, 176, 172, 140, 110, 162, 222, 255, 14, 38, 252, 82, 118, 138, 130, 124, 145, 199, 55, 162, 224, 80, 102, 141, 140, 57, 194, 36 };string string32Utf8 = Encoding.UTF8.GetString(bytes32);byte[] bytes70 = new byte[] { 239, 191, 189, 239, 191, 189, 239, 191, 189, 119, 77, 239, 191, 189, 239, 191, 189, 239, 191, 189, 110, 239, 191, 189, 239, 191, 189, 239, 191, 189, 14, 38, 239, 191, 189, 82, 118, 239, 191, 189, 239, 191, 189, 124, 239, 191, 189, 239, 191, 189, 55, 239, 191, 189, 239, 191, 189, 80, 102, 239, 191, 189, 239, 191, 189, 57, 239, 191, 189, 36 };string string70Utf8 = Encoding.UTF8.GetString(bytes70);首先,在 C# 中,两个字节数组在转换后产生相同的字符串,这与 PHP 不同。其次,与 PHP 相比,C# 中的字符串有所不同。PHP 中是否有一个函数在给定相同输入的情况下实际上会返回与 C# 的 Encoding.UTF8.GetString() 相同的输出?或者是否有我遗漏的东西实际上导致了 C# 和 PHP 之间的不同输出?
查看完整描述

1 回答

?
动漫人物

TA贡献1815条经验 获得超10个赞

您示例中的字节数组不是有效的 UTF-8。基本上,如果您在 C# 输出中看到 �� 符号,则表示Encoding.UTF8.GetString()使用替换字符来表示无法转换为输出字符的编码输入字节序列。

但是,您仍然可以在 PHP 中重现完全相同的行为Encoding.UTF8.GetString()

$bytes32 = [144, 204, 205, 119, 77, 176, 172, 140, 110, 162, 222, 255, 14, 38, 252, 82, 118, 138, 130, 124, 145, 199, 55, 162, 224, 80, 102, 141, 140, 57, 194, 36];

$string32 = \pack('C*', ...$bytes32);

$string32Utf8 = \mb_convert_encoding($string32, 'ASCII', 'UTF-8');


$bytes70 = [239, 191, 189, 239, 191, 189, 239, 191, 189, 119, 77, 239, 191, 189, 239, 191, 189, 239, 191, 189, 110, 239, 191, 189, 239, 191, 189, 239, 191, 189, 14, 38, 239, 191, 189, 82, 118, 239, 191, 189, 239, 191, 189, 124, 239, 191, 189, 239, 191, 189, 55, 239, 191, 189, 239, 191, 189, 80, 102, 239, 191, 189, 239, 191, 189, 57, 239, 191, 189, 36];

$string70 = \pack('C*', ...$bytes70);

$string70Utf8 = \mb_convert_encoding($string70, 'ASCII', 'UTF-8');


\var_dump($string32Utf8, $string70Utf8, $string32Utf8 === $string70Utf8);

我做的不同的事情:

  1. 由于 byte array 表示UTF-8 string,我们不能使用chr将其转换为二进制字符串。如chr函数文档中所述:

    此函数不知道任何字符串编码,特别是不能传递 Unicode 代码点值以生成多字节编码(如 UTF-8 或 UTF-16)的字符串。

    pack另一方面,函数可以处理各种类型的二进制数据格式。\pack('C*', ...$bytes32)意味着字节数组将被视为一系列无符号字符并打包成二进制字符串。

  2. utf8_decode函数有一个非常混乱的名字;它应该被命名为类似的东西,utf8_to_iso88591因为这正是它的作用:

    将包含以 UTF-8 编码的 ISO-8859-1 字符的字符串转换为单字节 ISO-8859-1

    如果我们想复制Encoding.UTF8.GetString()示例,我们真正需要做的是将 UTF-8 编码的二进制字符串转换为 ASCII。你可以使用mb_convert_encoding函数来做到这一点,就像这样:mb_convert_encoding($utf8String, 'ASCII', 'UTF-8')

希望这些评论会有所帮助!


查看完整回答
反对 回复 2023-04-21
  • 1 回答
  • 0 关注
  • 136 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信