我制作了一个宏\@Romankern
,它使罗马数字之间的字距为负数,从而使它们彼此更接近。我给它命名是\@Romankern
为了允许它与一起使用\pagenumbering
。
在我加载包之前,宏运行良好lastpage
。加载此包时,宏中断并告诉我:
! Undefined control sequence.
\@Romankern #1->\edef \temp
{\@Roman {#1}}\expandafter \@romkern \temp ...
我试图追踪错误源头,但失败了……很惨。我的宏到底出了什么问题,这么脆弱?
\documentclass{article}
\usepackage{lipsum}
\usepackage{lastpage}
\makeatletter
\def\@Romankern#1{%
\edef\temp{\@Roman{#1}}%
\expandafter\@romkern\temp\@empty}
\def\@romkern#1#2{%
\ifx#2\@empty
#1%
\let\next\relax
\else
#1\kern-0.07em%
\let\next\@romkern
\fi
\next#2}
\begin{document}
\pagenumbering{Romankern}
\lipsum[1-50]
\end{document}
答案1
的定义\@Romankern
不够稳健,因为它包含赋值(\def\temp{...}
、\let\next\@romkern
、...)。如果将标签写入文件.aux
,则不会执行赋值,并且\def\temp{...}
会变成类似于 的东西\def<the expansion of \temp>{...}
,这是<the expansion of \temp>
扩展 的当前含义的结果\temp
。在 的情况下,问题\temp
是未定义的,因此会引发错误。
以下示例定义了一个宏\@@Romankern
,该宏以纯数字作为参数,并将转到文件.aux
。 参数\@Romankern
(计数器值)到纯数字的转换以可扩展且因此可靠的方式完成(通过\expandafter
和)。 e-TeX 使\number
该宏变得可靠,可防止在写入文件时扩展。\@@Romankern
\protected
\@@Romankern
.aux
\documentclass{article}
\usepackage{lipsum}
\usepackage{lastpage}
\makeatletter
\def\@Romankern#1{%
\expandafter\@@Romankern\expandafter{\number#1}%
}
\protected\def\@@Romankern#1{%
\edef\temp{\@Roman{#1}}%
\expandafter\@romkern\temp\@empty\@empty
}
\def\@romkern#1#2{%
\ifx#2\@empty
#1%
\let\next\relax
\else
#1\kern-0.07em%
\let\next\@romkern
\fi
\next#2}
\begin{document}
\pagenumbering{Romankern}
Last page: \pageref{LastPage}
\lipsum[1-50]
\end{document}
该.aux
文件包含:
\relax
\newlabel{LastPage}{{}{\@@Romankern {10}}}
\xdef\lastpage@lastpage{\@@Romankern {10}}
\gdef\lastpage@lastpageHy{}
评论:
\@romkern
的呼唤\def\temp{\@Roman{#1}}% \expandafter\@romkern\temp\@empty\@empty
修改为包含二停止标记
\@empty
,因为\@romkern
总是期望二参数。但\temp
对于零或负数则为空。