標籤:

LaTeX 命令的可選參數不能有方括弧么?

我的例子是

documentclass{article}

ewcommand{ estcmd}[2][abc]{(#1)(#2)}

egin{document}

estcmd[[123]]{test}

end{document}

結果是

([123)(])test

看樣子 #1 是 [123,#2 是 ]。這是怎麼回事?


可選參數的左右方括弧在外觀上是一對括弧,直觀上它應該滿足成對出現嵌套配對之類括弧所應該有的語義。

但實際上左右方括弧是兩個模式匹配的定界符,TeX 找到第一個左方括弧和第一個右方括弧,分別作為它取參數的左右邊界。

——而與之相對,花括弧在 TeX 中真的是括弧,真的要滿足左右必須配對,嵌套內外有別之類的特性的。

這是什麼原因呢?我們可以剝開 LaTeX 的外衣,看看在下面 TeX 幹了什麼。

必需參數所使用的花括弧,是 TeX 宏語言的一部分,是一種規定的語法。在 TeX 中一個必需參數是這樣定義的:

deffoo#1{使用參數#1}

這裡 foo#1 表示 foo 後面有一個參數。這裡並沒有指出花括弧,後面的參數,或者是一個字元,或者是一個宏,或者是一個用花括弧括起來的整體。花括弧是一種確定的語法,表示 TeX 的分組,當宏展開時要讀參數的時候遇到分組,就會把這個分組剝開,把分組的內容作為整個參數。

而用來定義可選參數的方括弧,實際只是 TeX 宏命令模式的一部分,不是特殊的語法。左右方括弧沒有特殊性,用兩個左括弧或別的什麼也是一樣的。實際上,可選參數是一種用宏構造出來的語法糖,在定義中是先預讀後面的字元,判斷字元是什麼,然後用模式匹配的宏定義。用 TeX 的語法寫,就是:

deffoo{futurelet
extfooAux}
deffooAux{ifx
ext[%
expandafterfooOptArg
else
expandafterfooArg
fi}
deffooArg#1{使用必需參數#1}
deffooOptArg[#1]#2{使用可選參數#1,和必需參數#2}

下面可以用
foo{abc}
或者
foo[opt]{abc}

在上面的例子中:

  • foo 用來執行 futurelet,預讀 foo 後面的一個字元,把這個字元保存在
    ext 中,然後把控制權交給 fooAux。
  • fooAux 則判斷剛才保存的預讀字元是不是左方括弧,如果是就說明後面是可選參數,把控制權交給 fooOptArg;如果不是就說明沒有可選參數,把控制權交給 fooArg。
  • fooArg 就是一個普通的宏,接受一個參數。
  • fooOptArg 是一個具有命令模式的宏,它接收兩個參數,前一個參數 #1 用兩個字元串即左右方括弧隔開,後一個參數是右方括弧後面的普通參數。對於 fooOptArg 來說兩個參數都是必需的,如果 fooOptArg 後面不是這個模式就會報錯。

因此,可選參數的魔法之處分別來自於 futurelet 的預讀、ifx 的判斷、以後面 fooOptArg 的模式匹配。在這裡,如果把 fooOptArg 的參數模式換成別的以 [ 開頭的形式,也是可以的。

LaTeX 的
ewcommand 內部實現比上面說得複雜一些,但原理是一樣的。

按我們前面的示意性定義,現在就可以分析

estcmd[[123]]{test}

到底發生了什麼了。

  • 首先,TeX 使用 futurelet 預讀了 estcmd 後面的一個字元,保存了起來。
  • TeX 檢查了保存的那個字元,經過比較,發現確實是左方括弧。把控制權交給一個處理可選參數的宏。

  • 處理可選參數的宏的定義形如 fooOptArg[#1]#2,所以要進行模式匹配,也就是字元串查找啦。找到第一個左方括弧與第一個右方括弧之間的內容作為 #1,後面的作為 #2。所以我們看:

    estcmd [ [123 ] ] {test}

    第一個左方括弧後面的第二個左方括弧與數字 [123 是第一個參數 #1,而第一個右方括弧後面的單個字元第二個右方括弧 ] 是第二個參數 #2。至於後面的 {test},根本沒有在這個宏展開的分析之列。

這就是出現原來題目中結果的原因。

那麼,可選參數里到底能不能用方括弧呢?能。用花括弧的分組把它包起來,這樣用就可以了:

estcmd[{[123]}]{test}


推薦閱讀:

表示內積時,應該選擇leftlangle, left< 和 langle 中的哪一個?
有啥辦法能讓listings去檢查源代碼是不是和tex文件里一樣,而不是直接把那幾行input進來?
TeX Live 2015 有哪些值得關注的新特性?
如何從零開始,入門 LaTeX?
有沒有和writelatex(現在叫overleaf)一樣好用的本地tex IDE?如果沒有,為什麼沒有?

TAG:LaTeX |