如何在PHP中恢复两次编码转换后的文本编码?
如何用PHP恢复经历两次非UTF-8编码转换的文本?
如果只是将任意编码文本转成UTF-8,操作很简单:
$text = 'РєСѓСЂСЃ'; $text = mb_convert_encoding($text, "WINDOWS-1251", "UTF-8"); echo($text); // 输出: курс // 转换成功!
但如果文本经历过两次非UTF-8编码转换(比如从IBM866转WINDOWS-1251),情况就复杂了:
直接转换完全失效:
$text = '╬яЁхфхыхэшх л╚эЇюЁьрЎшюээюую яЁюфєъЄр╗'; $text = mb_convert_encoding($text, "IBM866", "WINDOWS-1251"); echo($text); // 输出: �??�?�?�?�?�?�?�?�?�?�? �?�??�?�?�?�?�?�?�?�?�?�?�?�?�?�? �?�?�?�?�?�?�?�?�?? // 转换失败
加入UTF-8转换步骤后有改善,但仍有问题:
$text = '╬яЁхфхыхэшх л╚эЇюЁьрЎшюээюую яЁюфєъЄр╗'; $text = mb_convert_encoding($text, "IBM866", "utf-8"); $text = mb_convert_encoding($text, "IBM866", "WINDOWS-1251"); $text = mb_convert_encoding($text, "utf-8", "IBM866"); echo($text); // 输出: Определение ?Информационного продукта? // 接近成功,但"?"应该是"«"和"»"
部分编码组合下所有方法都无效,比如从ISO-8859-1转IBM866:
$text = 'ਫ®¦¥¨¥ 4'; $text = mb_convert_encoding($text, "ISO-8859-1", "IBM866"); echo($text); // 输出: ???????????????????? 4 // 转换失败 $text = 'ਫ®¦¥¨¥ 4'; $text = mb_convert_encoding($text, "ISO-8859-1", "utf-8"); $text = mb_convert_encoding($text, "ISO-8859-1", "IBM866"); $text = mb_convert_encoding($text, "utf-8", "ISO-8859-1"); echo($text); // 输出: ?????????? 4 // 转换失败
我在Python中完成了相同转换,验证了原始文本的正确性:
text = '╬яЁхфхыхэшх л╚эЇюЁьрЎшюээюую яЁюфєъЄр╗' text = text.encode('cp866').decode('windows-1251') print(text) # 输出: Определение «Информационного продукта» # 转换成功 text = 'ਫ®¦¥¨¥ 4' text = text.encode('ISO-8859-1').decode('cp866') print(text) # 输出: Приложение 4 # 转换成功
PHP解决方案
Python中的encode是将字符串按指定编码转成字节流,decode是将字节流按指定编码解析成字符串。在PHP中,我们可以通过保留原始字节序列的方式模拟这个过程,核心是用单字节编码中转,避免字节丢失。
案例一:恢复IBM866→WINDOWS-1251转换后的文本
$text = '╬яЁхфхыхэшх л╚эЇюЁьрЎшюээюую яЁюфєъЄр╗'; // 1. 将UTF-8字符串转成ISO-8859-1编码(单字节,完整保留原始字节) $bytes = mb_convert_encoding($text, 'ISO-8859-1', 'UTF-8'); // 2. 将字节按WINDOWS-1251解析,再转成UTF-8输出 $original = mb_convert_encoding($bytes, 'UTF-8', 'WINDOWS-1251'); echo $original; // 输出: Определение «Информационного продукта»
案例二:恢复ISO-8859-1→IBM866转换后的文本
$text = 'ਫ®¦¥¨¥ 4'; // 1. 将UTF-8字符串转成ISO-8859-1编码,保留原始字节 $bytes = mb_convert_encoding($text, 'ISO-8859-1', 'UTF-8'); // 2. 将字节按IBM866解析,再转成UTF-8输出 $original = mb_convert_encoding($bytes, 'UTF-8', 'IBM866'); echo $original; // 输出: Приложение 4
原理说明
PHP的mb_convert_encoding默认会处理字符语义转换,而还原两次编码的文本时,关键是先获取第一次编码后的原始字节值,再用第二次编码规则解析。ISO-8859-1作为单字节编码,每个字节对应唯一字符,不会修改或丢失原始字节数据,完美模拟Python中encode得到字节流的过程。
内容的提问来源于stack exchange,提问作者Michael S
相关产品推荐
相关产品推荐

