这是一个有趣的案例。请问为什么案例 1 失败了?
\def\expandsecond#1#2{\begingroup\edef\x{\endgroup\unexpanded{#1}#2}\x}
\def\maybe@ic@{%
\ifdim\fontdimen\@ne\font>\z@\else
\maybe@ictrue
% Case 1:
\expandsecond{\@tfor\reserved@a:=}\nocorrlist\do{\t@st@ic}%
% Case 2 (original):
%\expandafter\@tfor\expandafter\reserved@a\expandafter:%
% \expandafter=\nocorrlist\do{\t@st@ic}%
\ifmaybe@ic\sw@slant\fi
\fi
}
\def\t@st@ic{%
\expandafter\let\expandafter\reserved@b\expandafter=\reserved@a\relax
\ifx\reserved@b\@let@token
\maybe@icfalse
\@break@tfor
\fi
}
错误来自
\textit{foof}
错误:
! Incomplete \iffalse; all text was ignored after line 163.
<inserted text>
\fi
<*> italic-correction.tex
通过以下修改,我遇到了同样有趣的问题:
\def\newtfor#1:={\new@tfor#1 }
\long\def\new@tfor#1#2\do#3{%
\edef\newfortmp{\unexpanded{#2}}%
\ifx\newfortmp\space\expandafter\@gobble\else\expandafter\@iden\fi
{\newtforloop#2\@nil\@nil\newtfor#1{#3}}%
}
\long\def\newtforloop#1#2\newtfor#3#4{%
\edef#3{\unexpanded{#1}}%
\ifx#3\@nnil\expandafter\@gobble\else\expandafter\@iden\fi
{#4\relax\newtforloop#2\newtfor#3{#4}}%
}
\long\def\breaknewtfor#1\newtfor#2#3{}
\def\maybe@ic@{%
\ifdim\fontdimen\@ne\font>\z@\else
\maybe@ictrue
% Case 1:
%\expandsecond{\newtfor\reserved@a:=}\nocorrlist\do{\t@st@ic}%
% Case 2:
\expandafter\newtfor\expandafter\reserved@a\expandafter
:\expandafter=\nocorrlist\do{\t@st@ic}%
\ifmaybe@ic\sw@slant\fi
\fi
}
\def\t@st@ic{%
\expandafter\let\expandafter\reserved@b\expandafter=\reserved@a\relax
\ifx\reserved@b\@let@token
\maybe@icfalse
\expandafter\breaknewtfor
\fi
}
编辑(2012/08/13)
以下是 M(N)WE:
\documentclass{article}
\usepackage{xspace}
\edef\x{catcode of comma=\the\catcode`\,\space,
\space catcode of stop=\the\catcode`\.}
%\show\x
%\show\nocorrlist
\makeatletter
\def\expandsecond#1#2{%
\begingroup\edef\x{\endgroup\unexpanded{#1}#2}\x
}
%\def\nocorrlist{.,\xspace} % source of the problem.
\def\maybe@ic{\futurelet\@let@token\maybe@ic@}
\def\maybe@ic@{%
\ifdim\fontdimen\@ne\font>\z@\else
\maybe@ictrue
% Case 1:
\expandsecond{\@tfor\reserved@a:=}\nocorrlist\do{\t@st@ic}%
% Case 2:
%\expandafter\@tfor\expandafter\reserved@a\expandafter
% :\expandafter=\nocorrlist\do{\t@st@ic}%
\ifmaybe@ic\sw@slant\fi
\fi
}
\makeatother
\begin{document}
\textit{foof}. \textit{foof}!
\end{document}
该问题是由我加载的一个包引起的:它确实如此\def\nocorrlist{.,\xspace}
。
答案1
正如 David Carlisle 所说,不要完全扩展\nocorrlist
。LaTeX 的斜体校正代码使用\futurelet
(在宏中\maybe@ic
)查找下一个标记。如果下一个标记是列表的元素\nocorrlist
,则斜体校正将被抑制。LaTeX 的原始定义仅将逗号和句点作为 catcode 为 12(其他)的标记。但用户可以通过其他包扩展列表(名称中没有@
)。扩展的标记也可以是宏,请参阅包biblatex
:
\appto\nocorrlist{\isdot\adddot\addperiod\addcomma}
我假设的目的\expandsecond
是在第一个参数之后扩展一个标记,以提供扩展的列表\@tfor
。它的行为类似于\expandafter
,不同之处在于它跳过一个标记列表而不是单个标记。插入的组使宏形式不可扩展。以下定义\expandsecond
扩展标记一次,而不是完全扩展。并且它不需要 e-TeX 的\unexpanded
:
\def\expandsecond#1{%
\begingroup
\long\def\x{\endgroup
#1
}%
\expandafter\x
}
可以通过使用宏来避免该组:
\def\expandsecond#1{%
\long\def\expandsecond@next{#1}%
\expandafter\expandsecond@next
}
然而,由于宏定义,该定义仍然不可扩展。
如果\newtfor
我不知道,你想改进什么。由于额外的宏扩展步骤( \@iden`),重新定义的效率可能会稍微低一些\@gobble,
。两种变体都可以处理标记列表中不匹配的条件。
对以下几行的注释
\edef\newfortmp{\unexpanded{#2}}%
\edef#3{\unexpanded{#1}}%
的目的\unexpanded
是为了防止扩张,因此最终的结果是(除了#
,参见“编辑”):
\def\newfortmp{#2}%
\def#3{#1}%
\@tfor
就像LaTeX 中循环的原始定义一样。
编辑:Joseph Wright 指出有一个例外。catcode 为 6 的标记(参数),通常是哈希字符#
,需要加倍,而无需\edef + \unexpanded
。