pdflatex 输出中的 Unicode 字符使用十六进制代码,无需 UTF-8 输入

pdflatex 输出中的 Unicode 字符使用十六进制代码,无需 UTF-8 输入

我想在 latex(/pdflatex)的输出中使用 Unicode 字符(对于韩语,即 Hangul:U+AC00 - U+D7A3;也可能是 U+1100 - U+11FF),而 LaTeX 源文件应像以前一样以 7 位 ASCII 编码。

我希望有类似于\ding{number}ZapfDingbats 的通过其十六进制码选择的 Unicode 内容,例如:

\unicodechar{bc73}

生成一个字符。输出应与之前一样:

latex -> dvips -> ps2pdfwr

到目前为止,我只见过源代码中使用 UTF-8 编码的 unicode 示例 - 这对我来说不是一个选择 - 并且通常使用 xelatex(破坏了我的书 - 我正在使用的软件包有问题)。我在 Xubuntu 12.10 下使用完全安装的 TeXLive 2012(Debian)(包括 CJK 软件包),因此原则上字体应该在那里。

我将非常感激任何答案,或至少是解决方案的提示 - 或者在最坏的情况下,说明为什么这根本不可能实现。

新增:请阅读上述事实。没有任何评论或答案与问题相关 - 看看这里的 unicode 问题 - 这个问题完全不同。没​​有德语变音符号或 Eurosign - 这很简单。编辑器或其他地方均禁止输入 Unicode 字符,仅在输出中可见。没有 XeLaTeX 或 LuaLaTeX。

仅举一个在上述条件下打印韩语字符的例子,或者说明为什么它不能与 latex/pdflatex 一起使用的原因。

答案1

理论上你可以用 ascii 输入你的整个文本,你只需要知道要使用哪些八位字节(8 位数据包):

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{textcomp}
\usepackage[utf8]{inputenc}

\begin{document}

Euro (€): ^^e2^^82^^ac

ä: ^^c3^^a4

\end{document}

主要问题是从 unicode 名称 (U+20AC) 获取 utf8-hex-notation (e282ac)。理论上可以计算 (并且 inputenc 在处理时会进行计算\DeclareUnicodeCharacter{20AC}{\texteuro}),但我不知道使用 inputenc 命令获取值的简单方法。

此输入符号也应适用于 cjk-package(带有 utf8 选项)。

使用 ucs-package (使用选项 utf8x 时加载),您可以使用命令\unichar。但您应该知道 ucs 可能与某些软件包发生冲突,例如,它在 biblatex 不兼容软件包列表中被提及。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{textcomp}
\usepackage[utf8x]{inputenc}

\begin{document}
\unichar{"00E4}
\unichar{"20AC}
\end{document}

我不知道它是否可以与 cjk 一起工作。

cjk 还提供了一些文本命令来输入符号,例如\Li4 \chun1。但我不知道这是否也涵盖了您的符号。

答案2

我认为enctex可以让你做到这一点。

首先,在 a 中写入 unicode 字符串\message{¾}(例如)。然后编译文件,您将在输出中看到多字节字符串 —^^c2^^be在此示例中。

现在,在文件顶部(或者更好的是,在格式中),输入\mubyte \someTeXCommand ^^c2^^be\endmubyte\mubytein=1

使用该选项编译您的文件(或您的格式)enc(它ini也需要选项,并且 LaTeX 可能需要etex顶部的选项),一切都应该很好 — 希望如此!

我个人在我的格式中保留了此类编码的列表,例如以 unicode 排版数学或在文本中使用特殊字符,如“...”

答案3

我刚刚遇到了一个问题,@UlrikeFischer 和 @RD6137 的回答基本上是正确的,但我会在这里发布一篇文章;虽然我不确定韩文字符本身,但我将重点关注问题的“Unicode 字符”和“十六进制码”部分;所有这些都经过了测试pdflatex

没有德语变音符号或欧元符号 - 这很简单。

其实并不简单(命令 \texteuro 在编码 T1 中不可用)——只是复杂性被textcomp包隐藏了。

首先,让我们关注一下输入。如果我在终端(bashLinux 上的 shell)中执行此操作:

$ echo -n € | hexdump -C
00000000  e2 82 ac                                          |...|
00000003

...我可以看到我在 shell 中输入的内容实际上是三个字节的序列:0xE2、0x82 和 0xAC。也许使用我的脚本会更容易utfinfo.pl

$ echo -n € | perl utfinfo.pl 
Got 1 uchars
Char: '€' u: 8364 [0x20AC] b: 226,130,172 [0xE2,0x82,0xAC] n: EURO SIGN [Currency Symbols]

这告诉我们,欧元符号的字符/字形在 Unicode 表中的条目编号为 8364(十六进制 0x20AC),并且编码(我猜是按照 UTF-8)为字节序列 226,130,172(十六进制为 0xE2,0x82,0xAC);与之前提供给我们的完全相同hexdump。这让我们想到了这一点:

禁止在编辑器或其他地方输入 Unicode 字符,

如果这是对@RD6137 的引用\message{¾},我相信这只是关于如何获取 Unicode 字符的实际字节序列的一种方法的建议。当您有像 U+20AC 这样的代码时,那只是 Unicode 名称 - 将其视为 Unicode 表中条目的整数索引。但那是不是UTF-8 中的实际字节序列。

而且,您唯一可以直接在 Latex 源文件中输入的是原始 UTF-8 字节,方法是使用双插入符号^^转义序列(我认为这后面的两个字符被解释为十六进制);因此拥有 U+20AC Unicode 索引/名称对您没有太大帮助 - 您需要实际的 UTF-8 字节序列 0xE2,0x82,0xAC。(如前所述,似乎没有方便/简单的 Latex 宏可以自动从 Unicode 索引映射到 UTF-8 字节序列)。

因此,通过^^e2^^82^^ac在 Latex 源文档中输入 ASCII 文本,Latex 将解析并解释它,就像您输入字节序列 0xE2,0x82,0xAC 一样 - 如果您将字符粘贴到文本编辑器中,并使用 UTF-8 编码保存文本文件,结果将完全相同。但是,如果在 Latex 文档中输入这三个字节,它们将被解释为单个 unicode 字符仅有的如果有的话\usepackage[utf8]{inputenc}!否则,Latex 会将它们映射到单独的字形,无论其当前字体设置如何。

这给我们带来了另一个问题 - 字体编码。考虑这个 MWE:

\documentclass{article}
% \usepackage[T1]{fontenc}
\usepackage{lmodern} % use font Latin Modern (lmodern / lmr)

\usepackage{fonttable}
\makeatletter
\def\myfontinfo{font: encoding \f@encoding, family: \f@family, series: \f@series, shape: \f@shape, size: \f@size, baselineskip: \f@baselineskip}
\makeatother

\begin{document}
  \typeout{\myfontinfo} % write to stdout
  \myfontinfo           % typeset in document
  , ^^e2^^82^^ac %
  \vspace*{-2em}
  \makeatletter
  %% \xfonttable{ encoding }{ family }{ series }{ shape }
  \xfonttable{\f@encoding}{\f@family}{\f@series}{\f@shape}
  \makeatother
\end{document}

如果你按原样编译它,那么 Latex 会自动假定它采用 OT1 编码,并打印字体表,如左图所示(单击可查看完整尺寸):

/tmp/测试-ot1.png /tmp/test-t1.png /tmp/test-ts1.png

...如果您启用[T1]{fontenc}并重新编译,Latex 将使用 T1 编码,生成完全不同的字体表 - 如中间图片所示。您会注意到,由于[utf8]{inputenc}未指定,Latex 在两种情况下都将其解释^^e2^^82^^ac为单个字符âĆň,与每种情况下的表格完全一致(字体表的阅读说明:左侧和顶部'是八进制;右侧和底部"是十六进制;因此%十进制为 37,'04x& '5='045八进制,"2x& '5="25十六进制;而-十进制为 45,'05x& '5='055八进制,"2x& "D="2D十六进制)。但是,您还会注意到 OT1 和 T1 都不包含欧元符号 - 那么它在哪里?事实证明,它在另一种名为的字体编码中TS1,位于上图最右边(只需[TS1]{fontenc}在上面的 MWE 中使用),其中它是十进制的字形编号 191('277八进制,"BF"十六进制)。

因此,如果我们仅添加\usepackage[utf8]{inputenc}上述示例,它现在就会崩溃:

! Package inputenc Error: Unicode char \u8:€ not set up for use with LaTeX.
See the inputenc package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                                  
l.15   , ^^e2^^82^^ac
                      %
? 

我们可以通过使用\DeclareUnicodeCharacter- 来从表面上解决这个问题,现在它需要十六进制的 Unicode 索引,而不是 UTF-8 字节序列。因此,假设您在 ;\DeclareUnicodeCharacter{20AC}{TheEURO}之后添加\usepackage[utf8]{inputenc},您会注意到,现在序列^^e2^^82^^ac结果只有单词TheEURO! 因此,\DeclareUnicodeCharacter当遇到与 Unicode 字符匹配的二进制/字节序列时,基本上可以为您调用一个宏 - 但这仍然在相同的当前字体编码中(上面 MWE 中的 OT1 或 T1)。

那么,为了排版欧元符号 - 无论您将其输入为 还是^^e2^^82^^ac正如我们现在讨论的启用时一样[utf8]{inputenc}- 都是通过调用\DeclareUnicodeCharacter某个宏来实现的,它将暂时切换到 TS1,并从那里输出字形编号 191。这似乎正是该textcomp包所做的(尽管我无法弄清楚编号细节):

$ grep euro `kpsewhich utf8enc.dfu`
\DeclareUnicodeCharacter{20AC}{\texteuro}

$ grep euro `kpsewhich textcomp.sty`
    \space\space 4 = 5 + \string\texteuro\MessageBreak
\DeclareOption{euro}{\DeclareEncodingSubset{TS1}{?}{4}}
\def\tc@fake@euro#1{%
\DeclareTextCommandDefault{\texteuro}
   {\CheckEncodingSubset\UseTextSymbol{TS1}\tc@fake@euro5\texteuro}

\DeclareUnicodeCharacter{20AC}{TheEURO}因此,如果您\usepackage{textcomp}在 之后添加而不是,您将在 Tex 源中\usepackage[utf8]{inputenc}看到以字形排版的 pdf 格式。^^e2^^82^^ac

回到韩文字符:如果我有这些字符,我就能找到它们的 Unicode 索引和 UTF-8 字节序列:

$ echo -n 각갓갥갷 | perl utfinfo.pl 
Got 4 uchars
Char: '각' u: 44033 [0xAC01] b: 234,176,129 [0xEA,0xB0,0x81] n: HANGUL SYLLABLE GAG [Hangul Syllables]
Char: '갓' u: 44051 [0xAC13] b: 234,176,147 [0xEA,0xB0,0x93] n: HANGUL SYLLABLE GAS [Hangul Syllables]
Char: '갥' u: 44069 [0xAC25] b: 234,176,165 [0xEA,0xB0,0xA5] n: HANGUL SYLLABLE GAELG [Hangul Syllables]
Char: '갷' u: 44087 [0xAC37] b: 234,176,183 [0xEA,0xB0,0xB7] n: HANGUL SYLLABLE GAEH [Hangul Syllables]

... 并使用,我们可以轻松地在 Latex 文档中[utf8]{inputenc}输入(十六进制的 UTF-8 字节序列) ;甚至可以为其定义一个处理程序,使用(使用十六进制的 Unicode 索引)——问题是,我们需要知道哪种字体^^ea^^b0^^81'각' HANGUL SYLLABLE GAG\DeclareUnicodeCharacter{AC13}{\myHangulGAGhandler}哪种字体编码包含该字形(以及在什么位置),以便我们可以编程\myHangulGAGhandler来选择和排版该字形。不幸的是,我对韩文/韩语字体一无所知(尽管我有一个CJKutf8例子如何在 LaTeX 中输入中文?,这可能作为起点很有用)。无论如何,使用上述代码检查 Latex 文档中的字体设置(也使用字体表),您知道这些文档可以很好地编译为韩文/韩语,可能会有所帮助。

否则,就直接使用 Unicode 索引十六进制输出字符而言\unicodechar{bc73},似乎没有方便的宏;尽管正如 @UlrikeFischer 指出的那样,\inputenc已经在后台执行了此操作 - 因为它必须将20ACin 转换\DeclareUnicodeCharacter{20AC}...为字节序列,以便稍后做出反应。然而,这非常复杂;您可以使用类似以下代码:

...
\usepackage[utf8]{inputenc}
\usepackage{trace}
\traceon
\DeclareUnicodeCharacter{20AC}{TheEURO}
\traceoff
...

.. 获取如下打印输出:

\UTFviii@tmp ->\UTFviii@three@octets €
{\expandafter}
{\expandafter}

\UTFviii@three@octets #1#2#3->\csname u8:#1\string #2\string #3\endcsname 
#1<-
#2<-�
#3<-�
{\expandafter}
....

...但在 shell 中,这看起来完全是错误的;如果.log在十六进制编辑器中打开该文件less,则可以看到:

...
\UTFviii@three@octets #1#2#3->\csname u8:#1\string #2\string #3\endcsname 
#1<-<E2>
#2<-<82>
#3<-<AC>
{\expandafter}
{\csname}
...

...inputenc基于此20ACUnicode 十六进制 ID,创建一个命令,其名称中包含原始 UTF 字节序列(0xE2、0x82、0xAC - 或至少是其第一个字节)!(实际上,我认为inputenc以某种方式将字节 0xE2 设为宏的别名\UTFviii@three@octets,这样它就会对扩展的 UTF-8 字符“作出反应”)。理解这一点不仅需要了解 Latex 内部结构,还需要了解实际的 UTF-8 编码,我认为这是这里的部​​分机制 - 不幸的是我没有。不过,希望这能有用...

相关内容