保留现场

在 LaTeX 编译中报错:Missing character: There is no (U+00A0) (U+00A0) in font JetBrains Mono。

探究原因

如果要搞清楚具体原因,就得从字符与字符编码说起了。解决办法直接跳到下一节吧。

字符,就是“a”,“A”,“你”等书写符号。

字符集,通常就是某种语言字符集合,比如英语就是ASCII 字符集,中文有GBK 字符集

注意,不是每种语言只对应一种字符集(比如 GB2312,GBK,GB18030 都包含了常用汉字,后者是前者的超集),而且字符集也不是只对应一种语言,例如 Unicode 字符集就包含所有语言字符,字符集只是设计者为了给字符编码(Code Point/Numbering)设计编码时,为了收录到命名的字符集合,但是通常设计者都为字符集设计了对应的编码规范。

字符编码,给字符集里的字符编号。

编码页,在 unicode 发明之前,各个地区都用 2 字节编码自己的字符集,相同的编码对应不同的字符,为了本地化,Windows 发明了编码页,来对应不同的字符集。

字符编码,对给定的字符编码编码成字节表示。

早期,字符被编号后,存储时就按照编号的方式存储,没有 encoding 的过程,后来发明 Unicode 后,发现如果按照 Unicode 的编号直接存储的话,对于英文字符就有很大存储浪费,因为任意字符都需要 2 字节存储,后来人们发明 UTF-8 这种编码方式,这样 UTF-8 就可以一个字节表示英文字符,2 个以上字节表示汉字字符。

字体,定义了字符的图形表示,现在的软件展示字符时用 Unicode 表示,字体是 Unicode 编码和字符图形的映射,而以往比如 WindowsCMD 控制台,没有对应 Unicode,则用编码页来区分,所以字体就是字符编码金和代码页到字符图形的映射。

文本文件存储在磁盘上,都是一系列的字节流,如果不告诉文本编辑器该文件的编码方式,编辑器会尝试用默认的编码(依赖于操作系统设置)又或者自己探测(detect,比如文件开头有 FFEF 或者 EFFF 字节就表明 UTF-16 编码,有很多 10,110 开头的字节,很可能是 UTF-8 编码)并尝试解码,如果没有猜对,那就会显示乱码

回到出错的问题,提示我们在字体 JetBrains Mono中没有U+00A0,我们搜索一下就知道这是一个 Unicode 字符NO-BREAK SPACE。我们通过上面的了解也知道了,字体就是字符编码到字符图像的映射,但是一个字体尤其是一些有专门用途的字体(比如 JetBrains Mono 设计初衷是为软件工程显示代码用的),它不会映射所有的字符,JetBrains Mono 这个字体里就没有映射 U+00A0。这就导致在 LaTeX 编译时无法在字体中找到对应的字符图像显示

所有解决办法就是要不替换掉这个字符,要不换个字体。

解决方法

VSCode 正则搜索\U00A0即可搜索到相关字符,将其替换成空格。

参考

字符,字符集,字符编码,编码页,字体 - 简书