[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[文本处理] 批处理65001代码页下多字节字符乱码问题初探

本帖最后由 buyiyang 于 2025-3-29 14:18 编辑

当要读写utf-8编码数据时,我们使用批处理要chcp 65001切换代码页,相应地,脚本也要utf-8编码。
但尽管如此,多字节字符仍然有时会乱码:
  1. chcp 65001
  2. echo,二
  3. echo,一
复制代码
实在让人困惑,对此我进行了一点简单的研究。
众所周知,批处理脚本是由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(前面提到的),或者直接在末尾添加一个单字节字符。如:
  1. chcp 65001
  2. echo,二二
  3. echo,一
复制代码
  1. chcp 65001
  2. echo,二2
  3. echo,一
复制代码
  1. chcp 65001
  2. echo,一
  3. echo,一
复制代码
1

评分人数

    • zzz19760225: 路过,不明觉厉,涨见识,学习。技术 + 1

啊 ,都utf8了 ,竟然还is_dbcsleadchar ,输出时貌似没有is_dbcsleadchar ,例如在936代码页的cmd窗口输入: echo °Ù¶ÈÍøÅÌͬ²½¿Õ¼ä ,能正确输出显示 真的是该is_dbcsleadchar的不is_dbcsleadchar ,不该is_dbcsleadchar的却is_dbcsleadchar???
还有 ,配合下面链接的帖子食用效果更佳
http://www.bathome.net/thread-68945-1-1.html

TOP

学习下,感谢楼主和2楼分享经验!
以前用chcp 65001 + utf-8编码,确实还出现乱码。

TOP

返回列表