\@startsection、hyperref 和 newunicodechar;需要保护吗?

\@startsection、hyperref 和 newunicodechar;需要保护吗?

在使用自定义环境工作时\@startsection,我发现在切换到newunicodechar定义我的unicode字符后,分段标题给出了这个特殊的输出:

在此处输入图片描述

以下是代码:

\documentclass{article}

\usepackage[colorlinks]{hyperref}

\newcounter{lemma}
\makeatletter
\def\lemmamark{\@gobble}
\newenvironment{lemma}[1]{\@startsection{lemma}{3}{-1em}{\baselineskip}{.1\baselineskip}{\bfseries}{Lemma: #1}}{}
\makeatother

\usepackage{newunicodechar}
\def\textomega{ω} \newunicodechar{ω}{\ifmmode \omega \else \textomega \fi}

\usepackage{fontspec}
\setmainfont[Ligatures=TeX]{STIXGeneral}

\begin{document}

\begin{lemma}{Properties of ω text}
    Some Test
\end{lemma}

\section{Properties of ω}
    More Testing

\end{document}

以下更改不产生任何影响:

  • 使用标准分段命令代替\@startsection(如示例输出所示)
  • 删除\ifmmode条件(我只是把它留在这里,这样你就能看到使用的原因\newunicodechar
  • 使用\protect内部\def\textomega
  • 使用\renewcommand\DeclareRobustCommand定义\textomega
  • 使用预定义的\textomega

我知道我可能unicode-math在这里用到它,但我仍然TeX Live 2011发现它在一般情况下不够用。

我只会发布一个关于如何解决这个问题的自我回答,但我更感兴趣的是:为什么会发生这种情况?hyperref这可能是或中的一个错误吗newunicodechar


这更奇怪了!对于其他类似的字符,不存在这样的问题。例如,ψ 代替 ω 可以与

\def\textpsi{ψ} \newunicodechar{ψ}{\ifmmode \psi \else \textpsi \fi}

答案1

软件包hyperref生成书签并尝试从 LaTeX 的节系统中捕获书签标题。最困难的步骤是将以 TeX 字符串形式给出的标题转换为适合 PDF 书签标题的字符串。首先,重新定义许多宏以获得更合理的书签输出。还hyperref利用 NFSS2 并使用编码PD1PUPDFDocEncoding 或 Unicode(PDF 书签字符串中只允许使用这两种编码)。然后展开字符串(\edef),并在之后的清理中检查标记。一个重要的步骤是\HyPsd@CheckCatcodes控制标记。例如,$用于切换到和从数学切换的被过滤掉。不幸的是,忘记了使用 e-TeX 定义的活动字符的情况 \protected。这是字符的情况,ω因为 \newunicodechar。它在行中得到扩展\ifcat#1A% letter\HyPsd@CheckCatcodes的扩展扩展ω\textomega,在PU编码中扩展为\83\311的八进制表示U+03C9。在这种情况下\8,由两个带有 catcode 12(其他)的标记组成,\ifcat 成功并且剩余的标记泄漏:3\311A来自预期标记比较的。

我将在 2012/07/30 v6.82w 中修复此问题hyperref。添加了对受保护活动字符的额外测试,并将这些字符替换为具有相同字符代码的 catcode 12(其他)的字符。但是,必须忽略活动字符的宏文本,因为该宏文本可能会打印其他内容。使用 定义的宏\protected未在 中展开\edef。支持此类宏和字符的唯一方法是为 增加这些宏的适当重新定义\pdfstringdef,例如:

\newunicodechar{ω}{ohm}
\pdfstringdefDisableCommands{%
  \def ω{ohm}%
}

顺便说一句,请记住,\text<charname>宏通常使用 NFSS2 系统 ( \DeclareTextSymbol\DeclareTextCommand、 ...) 定义。这些命令定义如何根据当前编码排版宏。它们会默默覆盖宏的先前定义。

答案2

以下任何更改都将删除带有“3\311A”的虚假行:

  • 删除hyperref
  • 删除以下语句\newunicodechar{ω}
  • 在……前面\protect放一个\textomega\newunicodechar{ω}
  • 使用\protect像这样的:

    \newcommand\unichar[3]{\newunicodechar{#1}{\protect{\ifmmode#2\else#3\fi}}}
    \def\textomega{ω} \unichar{ω}{\omega}{\textomega}
    

最后一种解决方案的优点是当使用大量此类语句时,代码简洁。


我发现了更多的事情。问题是,它fontspec覆盖了我的定义\textomega,因此当ω由 定义的\newunicodechar被扩展时,会使用fontspecs\textomega而不是我的。这解释了为什么另一方面使用来自\textomegalike 的不同命令\textpsi会起作用:当您尝试使用它时会被告知,\textpsi它在 EU1 编码中没有定义。

因此我可以在加载后简单地进行定义fontspec,但是有一个更好的解决方案,可以完全解决这个问题:

\newunicodechar{ω}{\ifmmode\omega\else ω\fi}

正如我得出的结论egreg 的答案之一,在 的参数中使用unicode字符本身是完全可以的\newunicodechar。所以现在不再\textomega需要了。

相关内容