![如何寫一個接受包含段落的參數的巨集?](https://rvso.com/image/391694/%E5%A6%82%E4%BD%95%E5%AF%AB%E4%B8%80%E5%80%8B%E6%8E%A5%E5%8F%97%E5%8C%85%E5%90%AB%E6%AE%B5%E8%90%BD%E7%9A%84%E5%8F%83%E6%95%B8%E7%9A%84%E5%B7%A8%E9%9B%86%EF%BC%9F.png)
我正在嘗試編寫一個接受包含段落的參數的巨集。如果您編寫一個普通的巨集並且其參數之一包含一個段落,它將中斷:
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\def\mymacro#1{#1}
\mymacro{This
contains a paragraph}
\end{document}
這會產生一個錯誤:
Runaway argument? {This ! Paragraph ended before \mymacro was complete. <to be read again> \par l.15
所以我嘗試重新定義\par
以擴展巨集的參數,但現在它不會停止編譯:
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\gdef\oldpar{\par}
\def\mymacro{\gdef\par{}\mymacroi}
\def\mymacroi#1{#1\gdef\par{\oldpar}}
\mymacro{foo
bar}
\end{document}
答案1
在編寫 TeX 時,處理一頁文件需要幾分鐘的時間,而且語法高亮也不是問題,因此如果有某種機制來檢測您是否忘記了}
.預設情況下, A\def
不允許使用\par
令牌,除非您明確表示它是 a \long\def
:
\def\mymacro#1{#1}
另一方面,LaTeX 預設情況下使用它,因此如果您使用正確的 LaTeX 命令(\def
不應在 LaTeX 文件中使用),則預設\newcommand
會使用 a \long\def
。如果您想要“短”,\def
那麼您可以使用\newcommand*
.
xparse
傳回短參數預設值,但允許您\long
使用+
參數修飾符定義巨集:
\NewDocumentCommand\mymacro{ m}{#1}% \def
\NewDocumentCommand\mymacro{+m}{#1}% \long\def
你的第二次嘗試很聰明,除了兩件事之外它本來可以成功。
首先是您正在使用\gdef\oldpar{\par}
然後\gdef\par{\oldpar}
。一旦您擴張 \par
你得到\oldpar
哪個,當擴展時,產生\par
哪個,當擴展時,產生\oldpar
哪個,當擴展時,產生\par
哪個,當擴展時,產生\oldpar
......永遠運行:/
在這種情況下,您需要使用\let
(或\global\let
具有全域效果):\let\oldpar\par
。這將建立\par
name的精確副本\oldpar
,它不依賴 is \par
。
其次,失控參數檢查是在較低層級實現的,與 的定義無關\par
,因此這會失敗並出現相同的錯誤:
\let\par\relax
\def\mymacro#1{#1}
\mymacro{foo
bar}
因為當 TeX 看到兩個\endlinechar
標記(預設是空格)時,TeX 會插入一個隱式\par
標記,這會引發Runaway argument
錯誤。知道了這一點,那麼:
\newcount\oldELchar
\oldELchar=\endlinechar
\def\mymacro{\endlinechar=-1\relax\mymacroi}
\def\mymacroi#1{#1\endlinechar=\oldELchar}
\mymacro{foo
bar}
不會引發錯誤,但新行將不再是空格。
答案2
用 定義的巨集的參數\def
不允許\par
使用標記。它也不允許空行,因為它們\par
在 TeX 處理文字輸入到標記的階段被轉換成空白行。請注意,重新定義\par
在這方面是沒有用的,因為它是恰恰不允許的標記\par
,與其意義無關。
解決方案:製作你的巨集\long
。
\long\def\mymacro#1{#1}
更好的解決方案:
\newcommand{\mymacro}[1]{#1}
因為內部\newcommand
使用。\long\def
此變體\newcommand*
使用\def
不帶前綴的方式。