分类
LaTeX

[转载]LaTeX中文解决方案集锦

原文链接
LaTeX 处理汉字的时候主要是用 CJK 宏包。这里收集了一些中文处理的常见问题和解决办法。

首段缩进

每一章,每一节的开头不缩进是很多人抱怨 “CJK 不符合中国人习惯”的头号原因。但是其实你可以改变这一切。CJK 提供的只是编码,而不是样式。

CJK是德国人设计的,他不懂中国人的习惯,但是他设计的编码方式完全可以为我们提供任何可能处理中文的“理论基础”,我们只需要制定自己的“有中国特色的样式”。中国人的样式必需由中国人自己来制定。这就使我想起了另外两个德国人,还有一位中国老人…… 🙂

通常英语文章在一节开始时的第一段是不缩进的。而在第二段就会缩进 \parindent 的距离。不赖烦的人请现在就在你的文档开头加入:


然后跳到下一个点子

如果你设置:

\setlength{\parindent}{2em}

你就可以得到像这样的缩进两个字的效果。但是第一段仍然没有缩进。为了让第一段缩进。你可以使用 indentfirst 宏包,它会使整篇文章的首段都有缩进。它其实只有两句话:

\let\@afterindentfalse\@afterindenttrue
\@afterindenttrue

如果你只想让你的某一节首行有缩进,可以这么做:

\makeatletter
\let\@afterindentrestore\@afterindentfalse
\let\@afterindentfalse\@afterindenttrue
\@afterindenttrue
\makeatother

这样之后的章节第一段都会缩进当前的 \parindent 那么多距离。

由于刚才我们用 \@afterindentrestore 存储了 \@afterindentfalse= 的定义。现在我们使用:

\makeatletter
\let\@afterindentfalse\@afterindentrestore
\@afterindentrestore
\makeatother

这下第一段又没有缩进了。你可以把这堆命令都用 \newcommand 设成新的命令,用起来就方便了。

中文书签

怎样用 hyperref 生成含有中文 bookmarkPDF 文件?
使用 hyperref 的时候加入 CJKbookmarks 选项就行了:


如果你使用 dvipdfm,需要再加一个 dvipdfm 的选项:


如果你想用 Unicodebookmark,就加上 unicode 选项:


好了,不耐烦的人请跳到下一个点子 🙂 不过如果你有兴趣看一下我昨天晚上怎么 hack hyperref,就看看我的分析:

我以前不知道 hyperref 已经有 CJKbookmarks 选项,所以昨天我想了一晚上,自己想出个方法,就是:

之后加上这样一句:

\pdfstringdefDisableCommands{
\let\CJK@XX\relax
\let\CJK@XXX\relax
\let\CJK@XXXp\relax
\let\CJK@XXXX\relax
\let\CJK@XXXXp\relax
}

完成!直接运行 pdflatex 两次就可以得到有中文 bookmark 的 PDF。嘿嘿!

由于 hyperrefCJK 宏包的不融合,以前如果要生成中文 bookmarkPDF 文件,需要进行以下工作:

在文档里 之后加入以下内容:

\PackageWarningNoLine{hyperref}{%
CJK characters are disabled in bookmarks}
\pdfstringdefDisableCommands{%
\let\CJK@ignorespaces\empty%
\def\CJK@char#1{\@gobbletwo}%
\let\CJK@charx\@gobblefour%
\let\CJK@punctchar\@gobblefour%
\def\CJK@punktcharx#1{\@gobblefour}%
}

第一次运行 pdflatex 后运行 energyaux2out 或者 toc2out 程序。
再次运行 pdflatex
这样做不但麻烦,而且有个不明显的坏处。由于 aux2outtoc2outauxtoc 文件里提取目录,它不能完全发挥 TeX 语言的作用,当你的章节里出现控制命令就会出错。比如,如果你有这样一个小节:

1. example of the \textsf{hhline} package

toc2out 会把 \textsf{hhline} 里的内容全部去掉,这样你得到的就是这样一个 bookmark: “example of the package”。”hhline” 就消失了!

其实 hyperref 设计时就考虑到了这种情况,它设计了一个命令:

\pdfstringdefDisableCommands

它的定义就是当生成 bookmark 时,我们需要对原来的文档进行的变化,比如,上面这个例子:

1. example of the \textsf{hhline} package

如果我们

\def\pdfstringdefDisableCommands{\let\textsf\relax}

就可以保留 hhlinebookmark 中。

这样我就有了一个中文 bookmark 的最简单的解决方案,完全可以不用外部程序。
方法就是:在 之后加上这样一句:

\pdfstringdefDisableCommands{
\let\CJK@XX\relax
\let\CJK@XXX\relax
\let\CJK@XXXp\relax
\let\CJK@XXXX\relax
\let\CJK@XXXXp\relax
}

这样,当生成 bookmark 时,GBK 的汉字被原封不动保留下来放到 .out 文件里。从而可以生成正确的中文 bookmark. 你还可以把

\let\CJK@XX\relax
\let\CJK@XXX\relax
\let\CJK@XXXp\relax
\let\CJK@XXXX\relax
\let\CJK@XXXXp\relax

都写到 hyperref.sty\def\pdfstringdef#1#2{….} 里,这样直接用 hyperref 就可以生成中文 pdf bookmark 了!

这种办法比起 hyperref 现在的方法有一个好处。因为汉字首先是通过 \CJK@XX, \CJK@XXX, … 转化为 CJK 内部代码的。hyperref 现在的方法相当于在输出 .out 文件的时候把 CJK 内部码又转回 GBK 码或者 Unicode。我的办法是直接把 \CJK@XX, \CJK@XXX, … 设为 \relax 让它们对汉字不起作用。这样汉字编码直接进入了 .out 文件,更加直接快速。

不过如果想要得到 Unicode 的汉字 bookmark, 需要实现更加直接的办法把 GBK 转到 Unic,我还不知道怎么转,编码的东西太烦人 😛 如果你的汉字不是 GBK, Unicode, 而是 HZ, BIG5, GB18030, 还是什么其它语言,… 你知道了这些,在将来的编码扩展中会更加容易解决问题,如果你遇到这种情况就可以在\pdfstringdefDisableCommands里加入你的东西。

汉字粗体

怎样让汉字可以显示粗体?

你是否发现,在 \section 标号的小节中,英语是粗体表示的,而汉字却没有变化?很多时候你想让汉字也成为粗体。

如果你用 \textbf{你好}, 你会发现根本没有变化。就像你在 Word 里使用“粗体”,打印出来也没有粗体效果一样。因为 Word 其实只是显示在屏幕上的时候让你看到很“粗”,但是其实你没有“粗宋体”这个字体,它打印时是不会打印出粗体的。Word 还有很多比如“下划线”之类的字体变化,但是实际上那些都是不符合排版的美学的。

CJK 宏包为没有粗体的人提供了一个“穷人”的办法:在 CJK 的字体定义文件中设置 \CJKbold. 看看你的 c19song.fd 里是否有以下内容:

\DeclareFontFamily{C19}{song}{}
\DeclareFontShape{C19}{song}{m}{n}{ CJK * gbksong}{}
\DeclareFontShape{C19}{song}{bx}{n}{ CJKb * gbksong}{\CJKbold}
\DeclareFontShape{C19}{song}{m}{it}{ CJK * gbksongsl}{}
\DeclareFontShape{C19}{song}{bx}{it}{ CJKb * gbksongsl}{}
\DeclareFontShape{C19}{song}{m}{sl}{ CJK * gbksongsl}{\CJKbold}
\DeclareFontShape{C19}{song}{bx}{sl}{ CJKb * gbksongsl}{}
\endinput

如果有的话,你用 \textbf{粗体} 就会得到一种“穷人的粗体”,它是把宋体汉字平移了三次重合在一起实现的,看看你的 CJK.sty 有如下定义:

\DeclareRobustCommand{\CJKsymbols}[2]{
\char #1\char #2\relax
\ifCJK@bold@
\hbox to \CJKboldshift{\hss\char #1\char #2}
\hbox to \CJKboldshift{\hss\char #1\char #2}
\fi}

这样的到的粗体显然是非常难看的,在PDF文件里显示明显有“彩虹”效果!根本不能用。所以 gbkfonts 生成的 fd 文件全部去掉了这个选项。

字体不是一个你想怎么变就可以怎么变的东西,它如果设计的时候就不是粗体,那你是不可能把它变成粗体的。如果你用LaTeX缺省的英文字体,一般的时候是 cmr10, 用粗体的时候其实用的是 cmbx10。 cmr10 和 cmbx10 是同一家族(Computer Modern)的两种不同的字体。cmbx 并不是 cmr 做了什么几何变换得到的,甚至 cmr10 也跟本不是 cmr5 扩大了两倍变出来的!

字体都是专门的设计,每一个尺寸的每一笔每一划都经过了字体设计者的精雕细琢。它们有的也可以变化大小,比如很多TrueType和Type1字体都可以随意变化尺寸,但是它们对每一个尺寸范围都设置了不同的参数,这并不是一个等比例的“缩放”过程。如果你把一个LaTeX文档里的 5pt TrueType 字体抓图抓下来,然后用一个图像处理程序(比如 ImageMagick)把图片扩大到原来的两倍,跟你在文档里直接用这个字体的 10pt 的效果肯定不一样,字体的长宽比例,甚至很多弧线的角度都有很大差别。

“原设计”只有放在“原尺寸”才是最好看的,更不用说“粗体”和“普通体”之间这么巨大的变化了。如果你简单的把普通字体经过什么几何变换得到一个“粗体”,那么它在美学上是过不了关的,你的字符会“不融合”,使得文档“黑白不均”,文档的整体效果会受到很大影响。

所以,你不应该把你正在用的这个“宋体”变“粗”,而必须去找专门的“粗宋体”来用。但是如果你没有,那就用黑体代替好了。

做法是这样:当要求使用粗体(bx)的时候,用黑体代换。你可以把你的 c19song.fd, c19kai.fd, … 都改成如下的样子:

\DeclareFontFamily{C19}{song}{}
\DeclareFontShape{C19}{song}{m}{n}{ CJK * gbksong}{}
\DeclareFontShape{C19}{song}{bx}{n}{ CJKb * gbkhei}{}
\DeclareFontShape{C19}{song}{m}{it}{ CJK * gbksongsl}{}
\DeclareFontShape{C19}{song}{bx}{it}{ CJKb * gbkheisl}{}
\DeclareFontShape{C19}{song}{m}{sl}{ CJK * gbksongsl}{}
\DeclareFontShape{C19}{song}{bx}{sl}{ CJKb * gbkheisl}{}
\endinput

这样黑体就会作为“粗体”出现在章节标题,粗体环境中了。

如果你运气好,你有一个真正的漂亮的“粗宋体”,比如它的名字叫做 gbkBsong。你就可以仿造上面在 c19song.fd 加入:

\DeclareFontShape{C19}{song}{bx}{n}{CJKb * gbkBsong}{}

如果你还有一个“粗楷体”叫做 gbkBkai。你就依葫芦画瓢,修改 c19kai.fd:

\DeclareFontShape{C19}{kai}{bx}{n}{CJKb * gbkBkai}{}

待续…

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据