Erweiterung in \addtocontents verstehen

Erweiterung in \addtocontents verstehen

Ich bin verwirrt darüber, wie die Erweiterung in funktioniert \addtocontents, oder genauer gesagt in \protected@write. So wie ich es verstehe, \addtocontentssollte im Wesentlichen sein zweites Argument mit erweitern \protected@edefund das Ergebnis in die aux-Datei schreiben. Mit diesem Verständnis würde ich erwarten, dass das Verhalten (bis auf einen gewissen Grad \protected@) dasselbe ist wie

\iow_shipout:Ne \@auxout
  {
    \exp_not:N \@writefile { #1 } { #2 }
  }

Aber wie das folgende MWE zeigt, verhalten sie sich unterschiedlich, wenn sie versuchen, eine Expansion innerhalb ihres Arguments mit zu verhindern \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}

Die AUX-Datei sieht aus wie

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

\naiveaddtocontentsDas Verhindern der Erweiterung mit ist genauso \exp_not:n, aber \addtocontentsnicht. Für meinen Anwendungsfall, in dem ich das Argument überhaupt nicht erweitern möchte, kann ich einfach dies verwenden \naiveaddtocontents. Aber warum funktioniert es nicht \exp_not:nwie fälschlicherweise erwartet in \addtocontents?

Antwort1

Der Befehl \addtocontentsverwendet \protected@write. Unten finden Sie die Definition von \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
}

Der relevante Teil ist \edef\reserved@a{\write#1{#3}}%. Wenn die obige Definition von \protected@writeim Dokument hinzugefügt und in der vorherigen Zeile \edefdurch ersetzt würde , ergibt sich \defdies in der .aux-Datei.\addtocontents{ lof }{ \exp_not:n { \abc } }\@writefile{lof}{\abc }

Allerdings \edeferfolgt bei eine zusätzliche Erweiterung, sodass die .aux-Datei \addtocontents{ lof }{ \exp_not:n { \abc } }entsteht .\@writefile{lof}{some text}

Daher funktioniert das Beispiel mit \edef, wenn zusätzlich Folgendes in der .aux-Datei \exp_not:nhinzugefügt wird :\addtocontents{ lof }{ \exp_not:n { \exp_not:n { \abc } } }\@writefile{lof}{\abc }

Antwort2

Schauen wir uns die Definition von an \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}}}

Mit deiner naiven Definition hättest du große Probleme, wenn du \labelim zweiten Argument ein hast \addtocontents. Aber lass das mal außen vor, es ist eine Formalität.

Angenommen, Sie möchten \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}

Die Konsole druckt

(\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>

und die auxDatei wird

\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}

Das ist nicht wirklich das, was Sie sehen möchten, oder? Lassen Sie uns das Problem beheben.

\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}

Die auxDatei hat nun

\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}

Im Grunde genommen \text_expand:nmacht es ungefähr dasselbe wie \protected@edef, lässt die resultierende Token-Liste jedoch in eingeschlossen \unexpanded.

Wenn Sie tun\exp_not:n (das heißt, \unexpanded), wird TeXNEINErweiterung, also erhalten Sie \abcund nicht seine Erweiterung.

Ohne \makeatletterund \makeatother:

\ExplSyntaxOn
\NewDocumentCommand { \naiveaddtocontents } { m m }
  {
    \iow_shipout:ce { @auxout }
      {
        \token_to_str:c { @writefile } { #1 } { \text_expand:n { #2 } }
      }
  }
\ExplSyntaxOff

Stattdessen \token_to_str:ckönnen Sie verwenden\exp_not:c

verwandte Informationen