温馨提示:若页面不能正常显示数学公式和代码,请阅读原文获得更好的阅读体验。

作者: 连小白 (连享会)
邮箱: lianxhcn@163.com

  • Title: 中文乱码不再棘手:用 Unicode 和 UTF-8 打通 Stata、Python、R
  • Keywords: 字符编码, ASCII, 字符串编码, 中文字符, 十进制, 十六进制, R语言

在数据分析中,大家经常遇到中文乱码问题,比如:

  • 在 .txt 和 .xlsx 文件中能够正常显示的数据文件,导入 Stata 或 Python 后,中文字段变成了 “学生”“æ•°æ�®” 一类的乱码;
  • 在 Stata、Python、R 之间导入/导出数据时,明明在 Stata 中显示正常,但读入 R 或 Python 后就变成乱码;
  • 用 Python 绘图时,图例或标题中的中文显示异常;

本文的目标是相对系统地整理这一块内容,帮助读者做到三件事:

  1. 理解 ASCII、Unicode、UTF-8 之间的关系,知道“编码问题”到底在折腾什么。
  2. 掌握一套通用的判断与选择原则:什么时候用 UTF-8,什么时候不得不用 GBK,如何识别编码错误。
  3. 在 Stata、Python、R 中,学会用少量命令完成“检测编码 → 转成 UTF-8 → 正确读写”的基本流程,从而在实际项目中减少踩坑。

1. 导言:棘手的乱码问题

很多同学第一次接触“编码问题”,往往是在如下几种情况下:

  • 从问卷平台或历史系统导出 CSV,导入 Python 或 R 时出现 UnicodeDecodeError
  • 从 Python 导出的 CSV 在 Stata 中打开后,所有中文字段都变成了“学生”“æ•°æ�®”一类的字符串;
  • R 写出的 CSV 在 Excel 中打开,中文出现问号或方块;
  • Stata 14 之前的旧版本与新版本之间互传数据,部分中文字段显示异常。

这些问题的共通点在于:“字符集统一”与“存储方式匹配”没有处理好。本质上,我们需要回答两个问题:

  1. 这份文本数据采用什么“字符集合”?也就是里面允许出现哪些符号(仅英文,还是中日韩等多语言)。
  2. 这些字符是用什么“规则”存进文件里的?即:是单字节、双字节,还是可变长度编码。

ASCII、Unicode、UTF-8 正是围绕这两个问题给出的三个不同层面的“标准”。理解这三者的关系,是解决所有编码问题的起点。

在技术层面上,一旦确定了目标策略——“项目内部统一采用 UTF-8 编码,所有中间文本文件都转换为 UTF-8 保存”——剩下的事情就变成了:

  • 检测已有文件的编码;
  • 必要时转换为 UTF-8;
  • 在各个工具中显式指定读写时的编码。

下面先从编码基础讲起,然后再回到 Stata、Python、R 的具体命令。

2. 编码基础:ASCII、Unicode 与 UTF-8 的核心逻辑

本节只抓住几个最关键的概念,并通过极简的例子帮助读者建立直观印象。想要进一步延伸阅读,可以参考:

2.1 ASCII:字符编码的基础框架

ASCII(American Standard Code for Information Interchange)是最早被广泛采用的字符编码标准之一,用 7 比特(即 0–127)来表示最常见的英文字母、数字、基本标点以及控制字符(如换行、回车等)。(维基百科)

  • 每个字符占用 1 个字节;
  • 主要面向英文环境;
  • 有了它之后,计算机可以用整数来表示与存储文本。

一个简单例子

  • 字符 A 的 ASCII 码是十进制 65,十六进制 0x41
  • 字符 a 的 ASCII 码是十进制 97,十六进制 0x61
  • 换行符 LF 的 ASCII 码是十进制 10,十六进制 0x0A

可以把 ASCII 理解为一张只有 128 行的小表格:每一行对应一个字符及其数值编码。后来的许多编码(包括 Unicode)都在这个基础之上扩展。

2.2 Unicode:多语言字符的统一编码体系

随着计算机在全球普及,仅用 128 个字符远远不够。不同国家和地区分别制定了各自的扩展编码(如 ISO-8859 系列、GB2312、BIG5、Shift-JIS 等),导致同一个字节序列在不同系统中可能被解释为完全不同的字符。(维基百科)

Unicode 的核心目标,是从“字符集合”的层面统一这些编码方案。它做了两件关键的事情:

  1. 为几乎所有语言的字符分配一个唯一的编号(码点),通常写作 U+4F60 这类形式;
  2. 不再把字符编码空间与具体语言绑定,而是试图用一个统一的标准覆盖所有文字系统。

因此可以理解为:

  • Unicode 是一个“巨大的字典”,里面记录了世界上常见字符的“统一编号”;
  • 它并不直接规定“如何把这个编号写入文件”,后者由具体的存储编码(如 UTF-8、UTF-16)来完成。(Unicode)

一个简单例子

  • 英文字母 A 的 Unicode 码点为 U+0041
  • 汉字 “你” 的 Unicode 码点为 U+4F60
  • 汉字 “数” 的 Unicode 码点为 U+6570

这里仅仅是给每个字符贴了一个“全球统一的编号”,至于这个编号如何转成字节序列,则交给 UTF-8、UTF-16 等具体实现。

温馨提示:若页面不能正常显示数学公式和代码,请阅读原文获得更好的阅读体验。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐