(来自OsbertWang的建议) @u40嗯……一会儿做个实验
在引入
ctex
包时,添加选项GBK
,然后将tex
文件编码改为GBK
,然后试试用pdflatex
与xelatex
能否编译
一些有关编码的前置知识(转译自egreg的著名回答):
inputenc
宏包允许用户直接在键盘内直接输入重音字符(accented characters),这可以让TeX
正确识别到fontenc
针对于输出PDF的字符结果,决定哪一种编码的字体将被用于打印字符到PDF内从结果上看,这两个宏包是互相独立的。但建议先加载 fontenc
再加载 inputenc
fontenc
的作用\usepackage[T1]{fontenc}
选择支持欧洲主要语言(德语、法语、意大利语、波兰语等)重音字符的输出字体编码。关键意义在于,若未使用 T1
编码,TeX 无法正确对含重音字母的单词进行断字(hyphenation)。inputenc
的作用
通过 \usepackage[<encoding>]{inputenc}
允许直接输入重音及其他特殊字符。<encoding>
需与文件编码一致(取决于操作系统(OS)和文本编辑器(text editor)设置)
pdflatex
进行编译时,若文件使用 Latin-1(ISO 8859-1) 编码,应调用:\usepackage[T1]{fontenc}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
却得到正确输出,可能因文件编码恰为 Latin-1,但存在例外(如输入 ß
会错误输出 SS
)。pdflatex
引擎)在TeX
开始读入文件时,其对文件编码(encoding)一无所知,TeX
只通过读取到的字符码(character number)执行它的行为
"a
的输入(两者正好coincide表现重合):Latin-1
编码的编辑器中,ä
存储为字符编号 228
;TeX
读取该字符时,inputenc
将其转换为 \"a
命令。fontenc
将 \"a
映射到 T1 编码字体 的 228
号字符(即 ä
的字形)。ß
的输入:223
,TeX
机器的读入在inputenc
宏的作用下,将字符码223
转换为\ss
fontenc
将\ss
映射到255
号字符,但实际上T1
编码是存在ß
这一字符的,这导致了一种错误的匹配UTF8
编码(xelatex
与lualatex
默认均基于此,且不再需要inputenc
宏包)当使用 \usepackage[utf8]{inputenc}
(且文件当然以 UTF-8 编码)时,情况略有不同。当文本编辑器显示 ä
或 ß
时,文件实际包含两个字节序列(byte sequences),分别为 <C3><A4>
和 <C3><9F>
。
第一个字节是一个前缀(prefix),包含一些信息,主要作用是表示这是一个双字节字符(two-byte character)。此时,inputenc
会将所有合法前缀设为活跃字符(active character),因此 <C3>
的行为类似于宏(macro);它的定义是查看下一个字符,然后根据 Unicode 规则解释整个字节对,并将其转换为对应的码点(code point),即分别转换为 U+00E4
和 U+00DF
。
其他前缀表示三字节或四字节组合(three or four byte combinations),但其行为本质上相同:它们不会多占用一个字符,而是吸收(absorb)两或三个后续字节,并执行到码点的转换。
在 ot1enc.dfu
和 t1enc.dfu
文件中,我们可以找到以下声明:
\DeclareUnicodeCharacter{00DF}{\ss}
\DeclareUnicodeCharacter{00E4}{\"a}
哦,等等!还有更多内容!是的,在这种情况下,inputenc
会与 fontenc
交互(而对于其他输入编码则不会):每加载一种输出编码时,对应的 .dfu
文件(Unicode 定义文件)会在文档开始前被读取。这就是为什么我倾向于始终先加载 fontenc
再加载 inputenc
(尽管并非绝对必要)。这些声明提供了必要的设置:组合 <C3><A4>
和 <C3><9F>
会被分别转换为 \"a
和 \ss
,此后一切工作方式与之前描述的 latin1
案例完全相同。
这里还有一个可能偶尔出现的问题(参见《Available Characters with iso-8859-1》)。Latin-1 编码在槽位(slot)0xA5
(十进制 165)处提供了日元符号(yen character)。根据上述描述,inputenc
的 latin1
选项会为此字符定义 \textyen
的转换,但 T1 输出编码并未为该符号预留槽位,因此输入 ¥
会导致 LaTeX 运行时错误(runtime LaTeX error)。此时必须加载一个为 \textyen
提供默认输出的包(package),例如 textcomp
。若使用 utf8 输入编码,也会遇到同样的问题。
唯一能被安全输入的字符是那些被输出编码覆盖的字符,或已通过输出编码定义合适渲染方式的字符。
当然以上这些对于使用xe
的用户来说并不需要,在用户层面来说,inputenc
并不是为xelatex
设计的,默认文档编码以及xelatex
引擎的读入编码均为UTF-8
,这意味着用户并不需要(也不允许)显式设置inputenc
;而xelatex
原生支持unicode
编码,对于这种情况下,要修改字体的设置可以通过fontspec
(其内部调用了fontenc
)进行调整,因此对于xe
用户来说,fontenc
也是没有必要被显式调用的。
回到ctex
的文档中的说明,关于文档编码,有如下的介绍:
从中我们知道在xelatex
以及lualatex
中,ctex-kit
均强制使用UTF-8
选项编码,而pdflatex
有两种选择,默认为UTF8
,仅仅对于历史遗留文档可使用GBK
编码。同时在vscode
上新建一个.tex
文件的默认编码也为UTF8
:
下面是一个用于测试的MWE:
\documentclass[<encooding option>]{ctexart}
\usepackage{lipsum,zhlipsum}
\begin{document}
现代社会以海德格尔的一句“一切实践传统都已经瓦解完了”为嚆矢。滥觞于家庭与社会传统的期望正失去它们的借鉴意义。
但面对看似无垠的未来天空,我想循卡尔维诺“树上的男爵”的生活好过过早地振翮。我们怀揣热忱的灵魂天然被赋予对超越性的追求,不屑于古旧坐标的约束,钟情于在别处的芬芳。
\lipsum[1]
\zhlipsum[1]
\end{document}
TeXlive2024
在windows11 24H2 内部操作版本为26100.2894
:尝试对此遍历下面的情况,列信息的含义为(<.tex文件编码>,<ctex-kit>指定的编码)
:
(GBK ,GBK ) | (UTF8 ,UTF8 ) | (GBK ,UTF8 ) | (UTF8 ,GBK ) | |
---|---|---|---|---|
pdflatex | (●'^'●)CASE1 | (●'◡'●) | (●'^'●)CASE3 | (●'^'●)CASE4 |
xelatex | (●'^'●)CASE2 | (●'◡'●) | (●'^'●)CASE2 | (●'◡'●) GBK 选项无效 |
lualatex | (●'^'●)CASE2 | (●'◡'●) | (●'^'●)CASE2 | (●'◡'●) GBK 选项无效 |
对于CASE1,编译出现如下错误,\zhlipsum
不支持以GBK
编码编译,但自己输入的中文可以被正确输出到PDF:
! Package zhlipsum Error: The current CJK environment uses "GBK" encoding, but
(zhlipsum) zhlipsum package has been loaded with the option
(zhlipsum) "encoding=utf8".
(zhlipsum) Please check the package options.
Type <return> to continue.
...
l.12
?
对于CASE2,编译出现大量字体缺失的警告,同时自己输入的中文出现乱码,zhlipsum
表现正常。下面仅为.log
的部分示例:
Missing character: There is no � (U+FFFD) in font [lmroman10-regular]:mapping=t
ex-text;!
Missing character: There is no ִ (U+05B4) in font [lmroman10-regular]:mapping=t
ex-text;!
Missing character: There is no � (U+FFFD) in font [lmroman10-regular]:mapping=t
ex-text;!
Missing character: There is no � (U+FFFD) in font [lmroman10-regular]:mapping=t
ex-text;!
Missing character: There is no � (U+FFFD) in font [lmroman10-regular]:mapping=t
ex-text;!
Missing character: There is no � (U+FFFD) in font [lmroman10-regular]:mapping=t
ex-text;!
Missing character: There is no � (U+FFFD) in font [lmroman10-regular]:mapping=t
ex-text;!
对于CASE3,编译出现如下的错误,且无法输出PDF文件:
! Package CJK Error: Invalid character code.
See the CJK package documentation for explanation.
Type H <return> for immediate help.
...
l.5
Ժ¸һ䡰һʵͳѾ߽ˡΪʸڼͥ...
?
Missing character: There is no in font cmr10!
! LaTeX Error: Invalid UTF-8 byte "FA.
对于CASE4,编译出现如下错误,我猜是在输入阶段TeX
不认识以UTF8
编码的“现代社会”,自己输入的文本乱码,且\zhlipsum
无法输出内容:
! LaTeX Error: Invalid UTF-8 byte "80.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
l.5 现代社会以海德格尔的一
句“一切实践传统都已经瓦解...
1.仅仅作为一个实验记录
2.在CASE2中为何\zhlipsum
能正常输出,但自己的中文内容出现乱码
3.现如今(2025年)如果拿到一个使用GBK
编码的.tex
文件,比较推荐尝试的编译方式是什么?(可以改用CTeX
套装编译试试,抑或使用GBK作为option的ctex-kit
在pdflatex
下编译?)
PS.由于我赶着吃饭,上面的内容应该有一些错漏,可以及时留下评论我会做修改。
case 1 是可以正常输出的,需要指定 \usepackage[encoding=gbk]{zhlipsum}
。
%%% 文件编码为 GBK!
\documentclass[GBK]{ctexart}
\usepackage{lipsum}
\usepackage[encoding=gbk]{zhlipsum}
\begin{document}
现代社会以海德格尔的一句“一切实践传统都已经瓦解完了”为嚆矢。滥觞于家庭与社会传统的期望正失去它们的借鉴意义。
但面对看似无垠的未来天空,我想循卡尔维诺“树上的男爵”的生活好过过早地振翮。我们怀揣热忱的灵魂天然被赋予对超越性的追求,不屑于古旧坐标的约束,钟情于在别处的芬芳。
\lipsum[1]
\zhlipsum[1]
\end{document}
case 2、3、4 都是同一个问题,TeX 不能正确解码 GBK 编码或 UTF8 编码的 bytes 为 Unicode Scalar Value。
可分别观察如下 python 代码的结果:
>>> b'\xd2\xbb'.decode('utf8')
'һ' ### 看看 case 3 的错误日志
>>> b'\xd2\xbb'.decode('gbk')
'一'
>>> '\ufffd\ufffd'.encode('utf8')
b'\xef\xbf\xbd\xef\xbf\xbd'
>>> '\ufffd\ufffd'.encode('utf8').decode('gbk')
'锟斤拷'
同一段 bytes 以不同的方式解码得到的是不同的 Unicode Scalar Value。如果一段 bytes 可以以 GBK 解码但不能以 UTF8 解码,就会得到错误,反之亦然。如果可以以两种方式解码,那看到的 Unicode Scalar Value 也大概率不是一样的,ASCII 除外。
TeX 看到的总是 bytes,人看到的是 Unicode Scalar Value,如果字体里没有某些 Unicode Scalar Value 的字形,就不能在 PDF 中显示。
对于 case 2,由于 zhlipsum
分别制作了 gbk 和 utf8 两个文件用来保存假文,所以,在这些文件中,文件的编码和 bytes 是匹配的,并且在 case 2 中,总是使用 utf8 这个文件,TeX 也总以 utf8 解码,所以不论 main 文件编码为何,TeX 总能读出假文正确的 Unicode Scalar Value。而 main 文件由于文件编码和解码方式不同,TeX 不能正确读取(解码)。
现在如果有 GBK 编码的 TeX 文件,最好的办法应该是统一转为 UTF8 编码,然后使用 CTeX-kit 默认的编码方式。