找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 8463|回复: 3

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

[复制链接]
发表于 2025-3-29 14:02:36 | 显示全部楼层 |阅读模式
本帖最后由 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技术 +1 收起 理由
zzz19760225 + 1 路过,不明觉厉,涨见识,学习。

查看全部评分

发表于 2025-3-29 20:15:41 | 显示全部楼层
啊 ,都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
发表于 2025-3-30 23:18:43 | 显示全部楼层
学习下,感谢楼主和2楼分享经验!
以前用chcp 65001 + utf-8编码,确实还出现乱码。
发表于 2025-12-5 18:48:04 | 显示全部楼层
牛B plus
最近因为处理UTF-8的文件,写了个UTF-8编码的脚本还真遇到了这个问题,虽然我多敲一个空行解决了,但是当时没理解问题出在哪。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 07:05 , Processed in 0.019423 second(s), 9 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表