
我試圖了解如何排版命令以在 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}
}
推理
我之所以想了解這一點是因為我似乎能夠用下面的程式碼來排版指令。我懷疑在某些情況下我的想法行不通。
也有一些限制:
- 包含帶有參數的命令,以便我可以將它們排版(在
NewEnviron
with中#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
,我們看到#1
is abc
,而#2
is 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