本帖最后由 buyiyang 于 2025-3-29 14:18 编辑
当要读写utf-8编码数据时,我们使用批处理要chcp 65001切换代码页,相应地,脚本也要utf-8编码。
但尽管如此,多字节字符仍然有时会乱码:复制代码 实在让人困惑,对此我进行了一点简单的研究。
众所周知,批处理脚本是由cmd逐行解析的。
实际上它一次性会读取8191个字节到缓冲区,然后以回车换行符为分割符进行分行,
再用MultiByteToWideChar函数转换成Unicode后进行解析和执行。
问题就出在分行逻辑和MultiByteToWideChar函数两个环节。
分行时cmd会逐字节处理缓冲区字符串,一次一个字节,遇到回车换行符就分行,
但是其中有个处理双字节的逻辑,使用is_dbcsleadchar判断双字节的前导字节,如果遇到DBCS前导字节(GBK前导字节范围为:0x81-0xFE)就一次性处理两个字节。
但utf-8字符有1—4个字节,多字节字符的字节大多在0x81-0xFE范围内(除了0x80),会被误认为前导字节,两个字节两个字节地处理,导致无法正确识别回车换行符。
按前面的例子,“echo,二”中“echo,”无前导字节,逐字节处理,而“二”(0xE4BA8C)中全是前导字节,先处理0xE4BA,再处理0x8C0D(0xOD是回车),然后处理0xOA(换行)。
所以就没有正确分行,“echo,二\r\necho,一”被作为一行让MultiByteToWideChar函数处理(逆向分析),中间有意外的回车换行符,就转换出了乱码,具体的不太了解这个函数。
所以关键就是不要让回车换行符分开,也就是让每行末尾连续的多字节字符组的字节数为偶数,或最后一个多字节字符的最后一个字节为0x80(前面提到的),或者直接在末尾添加一个单字节字符。如:- chcp 65001
- echo,二二
- echo,一
复制代码
- chcp 65001
- echo,二2
- echo,一
复制代码
复制代码 |