我对 中的扩展方式感到困惑\addtocontents
,或者更确切地说是 中的扩展方式\protected@write
。据我所知,\addtocontents
应该本质上用 扩展其第二个参数\protected@edef
并将结果写入辅助文件。根据这种理解,我预计行为(最多\protected@
)与 相同
\iow_shipout:Ne \@auxout
{
\exp_not:N \@writefile { #1 } { #2 }
}
但是正如下面的 MWE 所示,当他们试图用 来阻止论证内部扩展时,他们的行为有所不同\exp_not:n
。
\documentclass{article}
\makeatletter
\ExplSyntaxOn
\NewDocumentCommand { \naiveaddtocontents } { m m }
{
\iow_shipout:Ne \@auxout
{
\exp_not:N \@writefile { #1 } { #2 }
}
}
\ExplSyntaxOff
\def\abc{some text}
\begin{document}
bla
\ExplSyntaxOn
% this does what I expect
\protected@edef \l_tmpa_tl { \exp_not:n { \abc } }
\tl_show:N \l_tmpa_tl
% so does this
\naiveaddtocontents{ lof }{ \exp_not:n { \abc } }
% this does not
\addtocontents{ lof }{ \exp_not:n { \abc } }
\ExplSyntaxOff
\end{document}
辅助文件如下所示
\relax
\@writefile {lof}{\abc }
\@writefile{lof}{some text}
\gdef \@abspage@last{1}
因此,\naiveaddtocontents
使用 可以防止扩展\exp_not:n
,但\addtocontents
不能。对于我根本不想扩展参数的用例,我可以使用这个\naiveaddtocontents
。但为什么 不能\exp_not:n
像我错误预期的那样工作\addtocontents
?
答案1
该命令\addtocontents
使用。以下是from\protected@write
的定义:\protected@write
source2e
\long\def \protected@write#1#2#3{%
\begingroup
\let\thepage\relax
#2%
\let\protect\@unexpandable@protect
\edef\reserved@a{\write#1{#3}}%
\reserved@a
\endgroup
\if@nobreak\ifvmode\nobreak\fi\fi
}
相关部分是\edef\reserved@a{\write#1{#3}}%
。如果将上述的定义\protected@write
添加到文档中,并在上一行中将\edef
其替换为,\def
则在 .aux 文件中\addtocontents{ lof }{ \exp_not:n { \abc } }
给出。\@writefile{lof}{\abc }
然而,随着\edef
,会发生额外的扩展,使得.aux 文件中\addtocontents{ lof }{ \exp_not:n { \abc } }
出现。\@writefile{lof}{some text}
因此,如果添加\edef
附加内容,该示例就可以工作:在 .aux 文件中给出。\exp_not:n
\addtocontents{ lof }{ \exp_not:n { \exp_not:n { \abc } } }
\@writefile{lof}{\abc }
答案2
让我们看一下的定义\addtocontents
:
% latex.ltx, line 14289:
\long\def\addtocontents#1#2{%
\protected@write\@auxout
{\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}%
{\string\@writefile{#1}{#2}}}
\label
如果在 的第二个参数中有一个 ,那么按照你幼稚的定义,你会遇到大问题\addtocontents
。但我们先不考虑这一点,因为这是一个技术问题。
假设你想要\addtocontents{toc}{Hey, this is \textbf{boldface}}
。
\documentclass{article}
\makeatletter
\ExplSyntaxOn
\NewDocumentCommand { \naiveaddtocontents } { m m }
{
\iow_shipout:Ne \@auxout
{
\exp_not:N \@writefile { #1 } { #2 }
}
}
\ExplSyntaxOff
\makeatother
\begin{document}
Some text
\addtocontents{toc}{Hey, this is \textbf{boldface}}
\naiveaddtocontents{toc}{Hey, this is \textbf{boldface}}
\end{document}
控制台将打印
(\end occurred when \ifx on line 21 was incomplete)
(\end occurred when \ifx on line 21 was incomplete)
(\end occurred when \ifx on line 21 was incomplete)
(\end occurred when \ifmmode on line 21 was incomplete)</usr/local/texlive/2023
/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
并且aux
文件将具有
\relax
\@writefile{toc}{Hey, this is \textbf {boldface}}
\@writefile {toc}{Hey, this is \protect \unhbox \voidb@x \bgroup \edef l3backend-pdftex.def{boldface}\let \futurelet \@let@token \let \protect \relax \edef cmr{cmr}\edef cmss{cmss}\edef cmtt{cmtt}\def ##1,b,{}\series@check@toks {,ulm,elm,lm,slm,mm,sbm,bm,ebm,ubm,muc,mec,mc,msc,msx,mx,mex,mux,{}{},b,}\edef {}\edef b{b}\def ##1,m,{}\series@check@toks {,ulm,elm,lm,slm,mm,sbm,bm,ebm,ubm,muc,mec,mc,msc,msx,mx,mex,mux,{}{},m,}\edef {}\edef m{m}\protect \let }
\gdef \@abspage@last{1}
这可不是你想看到的,对吧?让我们来解决这个问题。
\documentclass{article}
\makeatletter
\ExplSyntaxOn
\NewDocumentCommand { \naiveaddtocontents } { m m }
{
\iow_shipout:Ne \@auxout
{
\exp_not:N \@writefile { #1 } { \text_expand:n { #2 } }
}
}
\ExplSyntaxOff
\makeatother
\newcommand{\abc}{some text}
\begin{document}
Some text
\addtocontents{toc}{Hey, this is \textbf{boldface} and \abc}
\naiveaddtocontents{toc}{Hey, this is \textbf{boldface} and \abc}
\end{document}
现在aux
文件将具有
\relax
\@writefile{toc}{Hey, this is \textbf {boldface} and some text}
\@writefile {toc}{Hey, this is \textbf {boldface} and some text}
\gdef \@abspage@last{1}
基本上,其作用\text_expand:n
与 大致相同\protected@edef
,但将生成的标记列表包裹在 中\unexpanded
。
如果你这样做\exp_not:n
(即\unexpanded
),TeX 将会这样做不扩展,所以你得到的\abc
不是它的扩展。
不带\makeatletter
和\makeatother
:
\ExplSyntaxOn
\NewDocumentCommand { \naiveaddtocontents } { m m }
{
\iow_shipout:ce { @auxout }
{
\token_to_str:c { @writefile } { #1 } { \text_expand:n { #2 } }
}
}
\ExplSyntaxOff
你可以\token_to_str:c
使用\exp_not:c