\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
\pdfstringdef
hyperref.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}%
}