bat,ps1,vbs,js脚本运行乱码报错?原来是文本编码的问题!
bat,ps1,vbs,js脚本运行乱码报错?原来是文本编码的问题!
| 脚本类型 | 运行环境 | 推荐保存编码 | 备注 |
|---|---|---|---|
.js |
Node.js | UTF-8 (无 BOM) | 现代 Web 开发标准,绝不使用 BOM。 |
.js |
WScript (双击运行) | ANSI (GBK) | 这是 Windows 宿主环境,对 UTF-8 支持极差,用 ANSI 才能正常 WScript.Echo 中文。 |
.bat |
CMD 命令行 | ANSI (GBK) | 默认情况下,中文版 Windows 的 CMD 只能读懂 ANSI。如果强行存为 UTF-8,CMD 会报错或乱码。 |
.ps1 |
PowerShell 5.1 | UTF-8 with BOM | 老版本 PowerShell(Windows 自带的蓝底黑字版本)需要靠 BOM 来识别 UTF-8。 |
.ps1 |
PowerShell 7+ | UTF-8 (无 BOM) | 微软后来出的跨平台新版 PS(黑底),已经默认并推荐使用标准 UTF-8。 |
.vbs |
WScript / CScript | ANSI (GBK) 或 UTF-16 LE | VBS 是非常古老的脚本,保存为 ANSI 是最稳妥的。如果在 Windows 记事本里,可以选择“ANSI”或“带有 BOM 的 UTF-16 LE” (记事本里叫 Unicode)。千万别用 UTF-8。 |
在 Windows 系统里,ANSI 根本不是一种特定的字符编码,而是一个“变色龙”。
简单来说,当你在 Windows 的记事本里选择保存为“ANSI”时,它的真实含义是:“使用当前电脑系统设置的默认本地语言编码”。
ANSI 到底等于什么?因国而异!
因为 ANSI 是跟随系统语言变化的,所以同一份标着“ANSI”的文件,在不同国家的电脑上,底层真正使用的编码是完全不同的(Windows 术语称之为“代码页 Code Page”):
- 在简体中文版 Windows 上: ANSI = GBK (代码页 936)
- 在繁体中文版 Windows 上: ANSI = Big5 (代码页 950)
- 在日本版 Windows 上: ANSI = Shift-JIS (代码页 932)
- 在美国/英文版 Windows 上: ANSI = Windows-1252 (代码页 1252)
为什么英文不乱码,而中文会乱码?
这就是“乱码”现象的万恶之源:
- 英文不乱码的原因: 无论是 GBK、Big5 还是 Windows-1252,它们都是从最基础的 ASCII 码扩展而来的。也就是说,它们的前 128 个字符(英文字母、数字、标点)的二进制数据完全一模一样。所以英文不管怎么换,都不会错。
- 中文乱码的场景(跨国/跨系统): 假设你在中文版 Windows 上新建了一个文本文档,写了“你好”,并保存为 ANSI(系统默默用 GBK 把它存成了几个字节的数据)。 然后,你把这个文件发给了一个使用英文版 Windows 的外国朋友。他的系统双击打开这个文件时,发现编码是 ANSI,于是它理所当然地用 Windows-1252(英文系统的本地编码)去强行解读那几个字节的数据——结果就是,中文拼图被拼成了奇怪的欧洲字母或乱码(比如
ÄãºÃ)。
为什么微软要叫它ANSI?
ANSI 的全称是美国国家标准学会(American National Standards Institute)。
在早期的 Windows 系统(Windows 3.1 和 Windows 95 时代),微软最初为了支持多种语言,引入了不同的代码页。当时英文默认的代码页是 Windows-1252,这个编码在一定程度上参考了 ANSI 组织制定的一份草案标准。于是,微软图省事,在系统里统一把“系统默认本地编码”的选项命名为了“ANSI”。
BOM是什么?
BOM 就是微软给文本文件强加的“私货标记”。
在现代的 Web 开发和编程中(包括你的 Hexo 博客、Node.js、JS、前端代码),BOM 是百害而无一利的。
BOM 最初是用来干嘛的?
在计算机底层,数据都是按“字节(Byte)”存储的。 像 UTF-16 或 UTF-32 这种编码,一个字符需要用 2 个或 4 个字节来表示。那么问题来了:这几个字节在内存里,是先存高位还是先存低位呢?
- Big-Endian(大端序):数据的高位字节存在前面(就像人头朝上站着)。
- Little-Endian(小端序):数据的低位字节存在前面(就像人倒立着)。
为了告诉计算机这个文件到底是“站着”还是“倒立”的,Unicode 标准规定,在文件的最开头加上一个特殊的隐形字符(代码是 U+FEFF)。计算机一读到这个字符,就知道该怎么去解析后面的字节了。这个隐形字符,就是 BOM。
为什么在 UTF-8 里,BOM 变成了“毒瘤”?
请注意:UTF-8 根本不需要 BOM!
UTF-8 的设计非常巧妙,它的字节顺序是固定的(每次按顺序读 1 到 4 个字节),不存在“大端”或“小端”的问题。所以在国际标准中,UTF-8 文件是不推荐加 BOM 的。
那为什么会有 “UTF-8 with BOM” 这种东西呢? 这又要怪微软了。
在早期,Windows 系统的默认编码是 ANSI。当 Windows 自带的“记事本”打开一个文件时,它不知道这到底是 ANSI 还是 UTF-8。为了偷懒,微软做了一个决定:
只要是用记事本保存的 UTF-8 文件,都在开头塞进去 3 个字节的 BOM(十六进制是
EF BB BF)。下次打开时,只要看到这 3 个字节,记事本就知道它是 UTF-8 了
BOM 是怎么让你的代码崩溃的?
因为这 3 个字节(EF BB BF)是隐形的(专业叫法叫“零宽无断空白字符”),你在编辑器里根本看不见它,但计算机程序在读取时却会被它坑惨。
现代的编程环境(Linux、Mac、Node.js、Web 浏览器)默认所有文件都是标准的 UTF-8,它们不认识也不理会 BOM 作为标记的作用,而是把它当成普通的文本内容读进去。
这会导致非常多诡异的 Bug,比如JS 脚本报错: 如果你的 .js 文件带了 BOM,Node.js 去运行它的第一行代码时,会发现前面多了一串无法识别的乱码字符,直接报 SyntaxError(语法错误),代码直接罢工。