pgfmanual-en-macros.tex 的第 1099-1121 行

pgfmanual-en-macros.tex 的第 1099-1121 行

我試圖了解如何排版命令以在 LaTeX 文件中使用。澄清,不是使用 LaTeX 建立文檔,而不是用 LaTeX 編寫有關使用 LaTeX 的文檔(就像在手冊中一樣)。據我所知,沒有任何術語可以區分 LaTeX 文件並使用 LaTeX 建立文件(不幸的是)。

pgfmanual-en-macros.tex 的第 1099-1121 行

https://www.ctan.org/pkg/pgf?lang=en

這段程式碼「看起來」它刪除了我的標誌,但我不知道。為什麼這是必要的?它是如何運作的?

{
  \makeatletter
  \global\let\myempty=\@empty
  \global\let\mygobble=\@gobble
  \catcode`\@=12
  \gdef\getridofats#1@#2\relax{%
    \def\getridtest{#2}%
    \ifx\getridtest\myempty%
      \expandafter\def\expandafter\strippedat\expandafter{\strippedat#1}
    \else%
      \expandafter\def\expandafter\strippedat\expandafter{\strippedat#1\protect\printanat}
      \getridofats#2\relax%
    \fi%
  }

  \gdef\removeats#1{%
    \let\strippedat\myempty%
    \edef\strippedtext{\stripcommand#1}%
    \expandafter\getridofats\strippedtext @\relax%
  }

  \gdef\stripcommand#1{\expandafter\mygobble\string#1}
}

推理

我之所以想了解這一點是因為我似乎能夠用下面的程式碼來排版指令。我懷疑在某些情況下我的想法行不通。

也有一些限制:

  • 包含帶有參數的命令,以便我可以將它們排版(在NewEnvironwith中#1)作為解釋下的示例(例如 \hello{input1} 然後#1在中使用NewEnviron將不起作用)

\documentclass{article}
\usepackage{fontspec}
\usepackage{environ}
\NewEnviron{command}[1]{% 
\begin{minipage}[t]{.3\textwidth}
\texttt{\string#1}
\end{minipage}
\hfill
\begin{minipage}[t]{.7\textwidth}
\BODY
\end{minipage}
\xdef\putcommandexample{\BODY}% Set BODY to variable http://tex.stackexchange.com/a/14392/13552
}%
\begin{document}
\section{Friendly Commands}
\begin{command}{\hello}
This command greets the reader in a friendly manner.
\end{command}
\begin{command}{\goodbye}
This command greets the reader in a friendly manner.
\end{command}
\end{document}

minipage任何有興趣的人的旁注:我還使用包將命令放在頁邊空白處,而不是s marginnote。看起來還不錯。

\NewEnviron{command}[1]{% 
\reversemarginpar\marginnote{\texttt{\string#1}}
\BODY
\par
}%

輸出

在此輸入影像描述

答案1

問題“為什麼有必要?”需要閱讀所有文件來源。它是如何工作的很容易看出。

此巨集\getridofats決定輸入流中其後面的內容是否\relax包含類別代碼12 @

然而,最好\removeats從一開始就看看如何運作。它應該接收一個命令名稱作為其支撐的爭論;首先它初始化\strippedat為一個空的令牌列表。然後就這樣了

\edef\strippedtext{\stripcommand#1}

它設定\strippedtext為包含命令名稱的字串,其中反斜線被刪除,因為它確實

\expandafter\mygobble\string#1

例如,\removeats{\abc@def}\expandafter\mygobble\string\abc@def首先轉換\abc@def為類別 12 個字元的字串(但@如果在上下文中呼叫宏,則出現在 後面的字母的類別代碼為 11 \makeatother),然後\mygobble吃掉反斜線。

完成此準備工作後,\expandafter\getridofats\strippedtext @\relax呼叫 ,它會在輸入流中產生以下標記:

\getridofats abc@def@\relax

查看 的定義\getridofats,我們看到#1is abc,而#2is def@。如果呼叫\removeats{\abcdef}已被看到,輸入流將包含

\getridofats abcdef@\relax

並且#1將是abcdef,而#2將是空的。

該巨集\getridtest定義為擴展為#2;在第一種情況下它不是空的,在第二種情況下它是空的。

此後,\ifx\getridtest\myempty在第二種情況下傳回 true,在第一種情況下傳回 false。

假設測試傳回 true(第二種情況)。然後

\expandafter\def\expandafter\strippedat\expandafter{\strippedat abcdef}

執行,它將#1(在本例中abcdef)附加到 的先前值\strippedat。它可能看起來毫無用處,因為\strippedat已被初始化為空。但我們稍後會看到“錯誤”情況下會發生什麼。

假設測試傳回 false(第一種情況)。然後

  \expandafter\def\expandafter\strippedat\expandafter{\strippedat abc\protect\printanat}%
  \getridofats def@\relax

完成:第一個區塊被附加到\strippedat,然後回調\protect\printanat巨集\getridofats來處理最後一個區塊。

在我看來,這不是寫得特別好的宏。然而,這些電話

\removeats\abcdef
\removeats\abc@def
\removeats\ab@cd@ef

結果\strippedat分別包含

abcdef
abc\protect\printanat def
ab\protect\printanat cd\protect\printanat ef

其中\printanat定義為

\def\printanat{\char`\@}

當然,\protect如果巨集是用 定義的,那麼絕對不需要\def\printanat{\char64 },但這是個人選擇。由於文件是用 LaTeX 處理的,我可能會選擇

\DeclareRobustCommand{\printanat}{\char`\@ }

(注意尾隨空格,沒有它是錯誤的)。

顯然,該機制用於避免@在文件中寫入字符.aux,從而避免其類別代碼(在讀取 LaTeX 輔助文件時設置為 11)出現問題。


expl3@版本,在類別代碼為 12 的上下文中發布。

\ExplSyntaxOn
\cs_new_protected:Npn \removeats #1
 {
  \tl_set:Nx \strippedat { \cs_to_str:N #1 }
  \tl_replace_all:Nnn \strippedat { @ } { \protect\printanat }
 }
\ExplSyntaxOff

相關內容