Shift_JIS

面向日语的字符编码。在旧系统中广泛使用,但向 UTF-8 的迁移正在推进。

Shift_JIS 是一种用于表示日语文本的字符编码。它于 1982 年被实现,此后在 MS-DOS 和 Windows 中作为标准使用。据传制定过程中有 ASCII 公司、微软、三菱电机等多家企业参与,而处于中心地位的据说是 ASCII 公司的技术人员。业界的实现先行出现,被定位为 JIS 规范则是 1997 年的 JIS X 0208 附录 1 (移位编码表示)。这一先后顺序,正是后文所述各实现之间差异的远因。它是结合 JIS X 0201 (半角英数字、半角片假名) 与 JIS X 0208 (汉字、全角字符) 的可变长度编码,是日本 IT 史上最具影响力的字符编码之一。

在 Shift_JIS 中,半角英数字用 1 字节表示,日语 (平假名、片假名、汉字) 用 2 字节表示。由于 UTF-8 中日语占 3 字节,仅就日语文本而言,字节效率是 Shift_JIS 更优。不过,Shift_JIS 收录的字符数仅限于约 7,000 个 (JIS 第一、第二水准),与 Unicode 的 14 万个以上相比大幅偏少。表情符号和部分汉字 (JIS 第三、第四水准) 无法表示。

Shift_JIS 有一个被称为"5C 问题"的著名技术课题。存在一些日语字符的第 2 个字节会出现反斜杠 (0x5C),例如"表""能""ソ"等,它们与 C 语言的转义字符相冲突,成为程序误动作的原因。这个问题也被称为"ダメ文字"(问题字符),在处理 Shift_JIS 的编程中始终需要注意。发生事故的地方是逐字节扫描字符串来进行分割或替换的处理。"表"是 0x95 0x5C、"能"是 0x94 0x5C、"ソ"是 0x83 0x5C 这样的排列,因此只看第 2 个字节就无法与日元符号或反斜杠区分开。一旦把这些符号选作分隔符就会崩溃,所以若要处理 Shift_JIS,唯一确实的规避办法是经由能够按字符单位判定边界的库,避免自制的字节单位处理。

向 UTF-8 的迁移在全球范围内已大致完成,在 W3Techs 的使用状况调查中,截至 2026 年 8 月有 99.0% 的网站以 UTF-8 提供。但在日本的商业环境中,仍有一些场景需要 Shift_JIS。理由包括:用 Excel 打开 CSV 文件时的默认编码是 Shift_JIS;银行和行政机关的遗留系统以 Shift_JIS 为前提;部分 EDI (电子数据交换) 规范指定使用 Shift_JIS 等。由于 CSV 的扩展名本身不带有编码的信息,结果会随接收方按什么打算去读取而改变。日语环境的 Excel 直接打开文件时会解释为 Shift_JIS 系 (CP932),所以用 UTF-8 写出的 CSV 如果不在开头加上 BOM,日语就会乱码。反过来若加上 BOM,在没有预想到 BOM 的程序导入时,开头的项目名会不一致,导致列的对应关系错乱。交给 Excel 就用 CP932 或带 BOM 的 UTF-8,交给程序就用不带 BOM 的 UTF-8,按用途分开输出才是可靠的做法。

在 Shift_JIS 与 UTF-8 相互转换时,有时会发生乱码。特别是"〜" (波浪号,U+301C) 与"~" (全角波浪号,U+FF5E) 的转换、"−" (全角减号) 与"-" (减号符号) 的转换,是容易成为麻烦根源的字符。Windows 的 CP932 (Windows-31J) 是 Shift_JIS 的扩展版,包含 NEC 特殊字符和 IBM 扩展字符,因此与纯粹的 Shift_JIS 之间的兼容性也需要注意。

从字符计数的角度来看,同一文本在 Shift_JIS 和 UTF-8 中字节数不同这一点很重要。日语 1 个字符在 Shift_JIS 中是 2 字节,在 UTF-8 中是 3 字节。在估算数据库的列大小和文件大小时,需要考虑所使用的编码。在字符计数工具中,同时显示字符数和字节数,把各编码之间字节数的差异可视化,就能提供对用户实务有帮助的信息。

分享这篇文章