PHP 的 utf8_decode 和 C# 的编码。UTF8.GetString 为相同的输入返回不同的输出
PHP's utf8_decode and C#'s Encoding.UTF8.GetString returning different outputs for the same input
我有这个 PHP 代码,它使用 utf8_decode():
将两个字节数组(一个有 32 个字节,另一个有 70 个字节)转换为 UTF-8 字符串
$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# 代码使用编码做同样的事情。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);
Console.WriteLine("string32Utf8: " + string32Utf8); // Writes ���wM���n���&�Rv��|��7��Pf��9�$
Console.WriteLine("string70Utf8: " + string70Utf8); // Writes ���wM���n���&�Rv��|��7��Pf��9�$
Console.WriteLine("string32Utf8 == string70Utf8: " + (string32Utf8 == string70Utf8)); // Writes true
首先,在 C# 中,两个字节数组在转换后产生相同的字符串,这与 PHP 不同。其次,与 PHP.
相比,C# 中的字符串不同
PHP 中是否有函数实际上 return 与 C# 的编码相同的输出。UTF8.GetString() 给定相同的输入?还是我遗漏了什么实际上导致 C# 和 PHP 之间的不同输出?
您示例中的字节数组 不是有效的 UTF-8。基本上,如果您在 C# 输出中看到 �� 个符号,则表示 Encoding.UTF8.GetString()
使用替换字符来表示无法转换为输出字符的编码输入字节序列。查看 DecoderReplacementFallback remarks 了解更多详情。
但是,您仍然可以在 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);
你可以在这里测试:https://3v4l.org/je8gf
我做的不同的事情:
由于字节数组表示UTF-8字符串,我们不能使用chr
将其转换为二进制字符串。如 chr
函数文档中所述:
this function is not aware of any string encoding, and in particular cannot be passed a Unicode code point value to generate a string in a multibyte encoding like UTF-8 or UTF-16.
另一方面,pack
函数可以处理各种类型的二进制数据格式。 \pack('C*', ...$bytes32)
表示字节数组将被视为一系列无符号字符并打包为二进制字符串。
utf8_decode
函数的名字很容易混淆;它应该被命名为 utf8_to_iso88591
因为这正是它的作用:
Converts a string with ISO-8859-1 characters encoded with UTF-8 to single-byte ISO-8859-1
如果我们想复制Encoding.UTF8.GetString()
示例,我们真正需要做的是将UTF-8编码的二进制字符串转换为ASCII。您可以使用 mb_convert_encoding
函数来实现,就像这样:mb_convert_encoding($utf8String, 'ASCII', 'UTF-8')
希望这些评论对您有所帮助!
我有这个 PHP 代码,它使用 utf8_decode():
将两个字节数组(一个有 32 个字节,另一个有 70 个字节)转换为 UTF-8 字符串$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# 代码使用编码做同样的事情。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);
Console.WriteLine("string32Utf8: " + string32Utf8); // Writes ���wM���n���&�Rv��|��7��Pf��9�$
Console.WriteLine("string70Utf8: " + string70Utf8); // Writes ���wM���n���&�Rv��|��7��Pf��9�$
Console.WriteLine("string32Utf8 == string70Utf8: " + (string32Utf8 == string70Utf8)); // Writes true
首先,在 C# 中,两个字节数组在转换后产生相同的字符串,这与 PHP 不同。其次,与 PHP.
相比,C# 中的字符串不同PHP 中是否有函数实际上 return 与 C# 的编码相同的输出。UTF8.GetString() 给定相同的输入?还是我遗漏了什么实际上导致 C# 和 PHP 之间的不同输出?
您示例中的字节数组 不是有效的 UTF-8。基本上,如果您在 C# 输出中看到 �� 个符号,则表示 Encoding.UTF8.GetString()
使用替换字符来表示无法转换为输出字符的编码输入字节序列。查看 DecoderReplacementFallback remarks 了解更多详情。
但是,您仍然可以在 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);
你可以在这里测试:https://3v4l.org/je8gf
我做的不同的事情:
由于字节数组表示UTF-8字符串,我们不能使用
chr
将其转换为二进制字符串。如chr
函数文档中所述:this function is not aware of any string encoding, and in particular cannot be passed a Unicode code point value to generate a string in a multibyte encoding like UTF-8 or UTF-16.
pack
函数可以处理各种类型的二进制数据格式。\pack('C*', ...$bytes32)
表示字节数组将被视为一系列无符号字符并打包为二进制字符串。utf8_decode
函数的名字很容易混淆;它应该被命名为utf8_to_iso88591
因为这正是它的作用:Converts a string with ISO-8859-1 characters encoded with UTF-8 to single-byte ISO-8859-1
如果我们想复制
Encoding.UTF8.GetString()
示例,我们真正需要做的是将UTF-8编码的二进制字符串转换为ASCII。您可以使用mb_convert_encoding
函数来实现,就像这样:mb_convert_encoding($utf8String, 'ASCII', 'UTF-8')
希望这些评论对您有所帮助!