在章节标题中使用 \input 与 \scantokens (使用 hyperref 包)

在章节标题中使用 \input 与 \scantokens (使用 hyperref 包)

\scantokens当我尝试将章节标题与包一起使用时,遇到了以下问题hyperref(没有这个包,一切都很好)。

\protect\input...可以出现在章节标题中。但使用 的相同构造\scantokens会失败(“第二”):看来 hyperref 在创建 pdf 字符串时并不关心保护。使用\unexpanded{\protect\scantokens{...}}防止扩展(“第五”),但如果我们省略\protect,它会再次崩溃(“第三”)。使用两个\unexpanded也可以(“第四”)。

\documentclass{article}
\usepackage{hyperref}
\begin{document}
\tableofcontents
\section{\protect\input{data}}
% \section{\protect\scantokens{Second}}
% \section{\unexpanded{\scantokens{Third}}}
\section{\unexpanded{\unexpanded{\scantokens{Fourth}}}}
\section{\unexpanded{\protect\scantokens{Fifth}}}
\end{document}

(该文件data仅包含First(或其他内容)。)上面的示例可以编译,但删除其中一个%将导致编译失败。

为什么我们需要两层不扩展/保护?有没有更简洁的方法来实现这一点?

上下文:我编写了一个包 (cprotect.dtx),通过将参数写入文件并\input对其进行 ting,可以逐字逐句地记录大多数命令的参数。现在,使用它\scantokens比编写几十个辅助文件更好。

答案1

我的另一个答案是错误的方法。它行不通,因为基本上不可能延迟扩展\pdfstringdef

相反,我们要做的就是阻止 [e-]TeX在 末尾发出Runaway definition/信号;它这样做是因为认为生成的标记来自名为“ ”的文件,并且 的字符串参数最终成为 的“替换文本” (巧妙地伪装成),如以下摘录所示(参见! File ended while scanning definition ...\scantokens\scantokens\pdfstringdef\xdef\Hy@temp\pdfstringdefhyperref.dtx/hyperref.pdf完整来源):

      \let\Hy@temp\xdef
      \let\def\HyPsd@DefCommand
      \let\gdef\HyPsd@DefCommand
      \let\edef\HyPsd@DefCommand
      \let\xdef\HyPsd@DefCommand
      \let\futurelet\HyPsd@LetCommand
      \let\let\HyPsd@LetCommand
      \Hy@temp#1{#2}%

(显然,Knuth 从来没有想到有人可能想要在扩展\edef/期间读取一个文件\xdef;我甚至没有在“TeX:程序”索引中找到这个确切的错误消息!)

我以为这会更加棘手,但是他们告诉我只需\noexpand在参数的右括号前插入一个\scantokens,它们似乎是正确的。例如,以下内容生成具有工作轮廓的 PDF,而不会触发任何警告:

\documentclass{article}
\usepackage{hyperref}

\begin{document}

\section{\scantokens{Test\noexpand}}

\end{document}

警告

不幸的是,如果你需要重新分配,这可能对你没有太大帮助\catcode,因为那些是命令,并且胃不可用\pdfstringdef

如果这是一个问题,你可以尝试使用\detokenize,因为它被硬编码为生成类别 12(对于大多数字符)和 10(对于字符 32,ASCII 空格字符)的字符标记——我不禁在e-TeX 手册(见第 14 页)当我在寻找避免“失控定义”问题的方法时。

答案2

忘记以下内容:它不会有帮助;\pdfstringdef 将从扩展中删除任何无法识别的控制序列——我们必须在那时进行扩展。现在我们要做的就是弄清楚为什么它不起作用了……

我建议\protect\pdfstringdefPreHook钩子中添加适当的重新定义\pdfstringdefDisableCommands. 可能情况如下:

\pdfstringdefDisableCommands{%
  \def\protect{\noexpand\protect\noexpand}%
}

相关内容