\addtocontents의 확장 이해

\addtocontents의 확장 이해

\addtocontents확장이 에서 , 더 정확하게는 에서 어떻게 작동하는지 혼란스럽습니다 \protected@write. 내가 이해하는 바에 따르면 \addtocontents기본적으로 두 번째 인수를 확장 \protected@edef하고 결과를 aux 파일에 써야 합니다. 이러한 이해를 통해 나는 동작이 (최대 a까지 \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}

aux 파일은 다음과 같습니다

\relax 
\@writefile {lof}{\abc }
\@writefile{lof}{some text}
\gdef \@abspage@last{1}

그래서 \naiveaddtocontents확장을 방지하고 있지만 \exp_not:n그렇지 \addtocontents않습니다. 인수가 전혀 확장되는 것을 원하지 않는 사용 사례에서는 this 을 사용할 수 있습니다 \naiveaddtocontents. 그런데 \exp_not:n에서 내가 잘못 예상한 대로 작동 하지 않는 이유는 무엇입니까 \addtocontents?

답변1

이 명령 \addtocontents\protected@write. 다음은 \protected@writefrom 의 정의입니다 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문서와 이전 줄에 추가되면 는 .aux 파일에 제공 \edef됩니다 .\def\addtocontents{ lof }{ \exp_not:n { \abc } }\@writefile{lof}{\abc }

그러나 를 사용하면 .aux 파일에 제공되는 \edef추가 확장이 발생합니다 .\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순진한 정의를 사용하면 에 대한 두 번째 인수에 a가 있으면 큰 문제가 발생할 수 있습니다 \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

관련 정보