常规PS/CMD窗口无法读取Unicode的问题排查
我用Lua 5.4编写了如下测试脚本:
--test.lua local s = io.read() for i=1, utf8.len(s) do local cp = utf8.codepoint(s,i) print(cp) print(utf8.char(cp)) end
在Windows Terminal应用内的PowerShell终端中,执行chcp 65001切换编码页后运行脚本,输入abæ,脚本能正确识别非ASCII字符“æ”,输出其编码点230及对应字符:
C:\>chcp 65001 Active code page: 65001 C:\>lua test.lua abæ 97 a 98 b 230 æ C:\>
但在**常规独立PowerShell窗口(非Windows Terminal内嵌)**中执行相同操作时,“æ”无法被正确解析,输出编码点为0:
C:\>chcp 65001 Active code page: 65001 C:\>lua test.lua abæ 97 a 98 b 0 C:\>
最初误以为是VS Code终端的问题,后来确认是常规PowerShell/CMD窗口与Windows Terminal内嵌PS终端的差异导致。两种环境下执行以下命令的输出完全一致:
([console]::InputEncoding, [console]::OutputEncoding, $OutputEncoding) | Select-Object -Property EncodingName, WindowsCodePage, Codepage
输出结果:
EncodingName WindowsCodePage CodePage ------------ --------------- -------- Unicode (UTF-8) 1200 65001 OEM United States 1252 437 US-ASCII 1252 20127
请问这种差异产生的原因是什么?
原因分析
这个差异的核心在于两种终端窗口对控制台输入的底层处理机制不同:
Windows Terminal的输入处理
Windows Terminal基于现代控制台子系统(ConPTY)实现,它会直接将用户输入的UTF-8字符完整传递给子进程(如Lua解释器)。切换编码页到65001后,ConPTY会确保输入的字节流严格遵循UTF-8编码,Lua的io.read()能正确读取到“æ”对应的UTF-8字节序列0xC3 0xA6,进而解析出编码点230。传统PowerShell/CMD窗口的输入处理
传统控制台窗口(旧版conhost.exe)对chcp 65001的支持存在兼容性缺陷:
- 虽然表面上编码页切换到了UTF-8,但旧版控制台在处理非ASCII输入时,会尝试将字符转换为当前OEM编码(此处为437),而“æ”并不存在于OEM 437编码中,转换失败后会被替换为空字符(0x00),也就是你看到的编码点0。
- 即使
[console]::InputEncoding显示为UTF-8,旧版控制台的实际输入路径并没有完全遵循这个设置,底层仍会走OEM编码的兼容逻辑,导致非ASCII字符丢失或被替换。
简言之,Windows Terminal的ConPTY彻底解决了旧版控制台的UTF-8兼容性问题,而传统窗口仍受限于历史遗留的编码处理逻辑,即便表面编码设置一致,实际输入处理的底层实现完全不同。
内容的提问来源于stack exchange,提问作者peterpop

