一、注释与空白
LaTeX3 仍以 % 为注释符,% 至行未的所有内容都会被忽略。dtx 格式注释规则较复杂,但规则仍与 LaTeX2e 一样。
除了少量殊情况外,LaTeX3忽略所有空白(包括空格、制表、换行符等)。而 ~
和 '\ ' 可以用来生成空白,不会被忽略(行首除外)。
如下示例:
\documentclass{article}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn\my_funa:nn#1 #2
{ #1 #2 #1 }
\my_funa:nn{ Hello World! }{~}{ Hello World! }
\ExplSyntaxOff
\end{document}
等效于:
\documentclass{article}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \my_funa:nn #1#2
{ #1 #2 #1 }
\my_funa:nn { Hello World! } { ~ }
{ Hello World! }
\ExplSyntaxOff
\end{document}
将输出:HelloWorld! HelloWorld!HelloWorld!
。(接下来的内容解释原因)
二、函数
LaTeX3 内置了一系列的预定义函数,同时还支持用户自定义新函数。
函数是简单的带参或不带参宏,函数会展开(Expand)则为置换文本(Replacement Text)。
2.1 特殊的函数
LaTeX3 预定义的函数中,几乎大部分都符合上一节介绍的命名规则。但因功能需要,还是有少量的函数不符合命名规则。所幸,这些函数并不多,而且很容易识别。
前面介绍的\ExplSyntaxOn
与\ExplSyntaxOff
就是两个典型的例子。更多的函数将在后续章节中介绍。
启用与禁用 L3 语法
由于 L3 使用了 _
和 :
符号来提供结构,这与 LaTeX2e 本身的语法不兼容。所有要使用 L3 语法时,必须先用\ExplSyntaxOn
来启用;而要用恢复 LaTeX2e 语法时,则需要使用 \ExplSyntaxOff
来禁用。
(如果你写过 LaTeX2e 宏包,可以把它们看作和\makeatletter
与 \makeatother
的功能“类似”。)
后面讲解示例时,不再解释这两个命令了。
2.2 参数
函数可以带参数,也可以不带参数。使用标准命名规则的函数,其参数会由参数说明符指示出来,包含参数数量及参数类型等。
在函数定义时,可以使用 #1
、#2
等符号来引用参数(其它语言中的形参)。LaTeX3 最多支持 9 个参数。
在执行(展开)函数时,会从函数后面的输入流中吸收参数(其它语言中的实参),并按顺序被传递给函数。
2.3 使用已有函数
在示例中,首先使用了\cs_new:Npn
函数来定义一个新函数,它需要三个参数:函数名(N
)、函数参数(p
)和置换文本(n
)。
实际执行时,会按如下方式传递参数:
将 \my_funa:nn
传递给第一个参数(N
类型,吸收一个凭据);将 #1#2
传递给第二个参数(p
类型,吸收一个参数列表);将 { #1 #2 #1 }
传递给第三个参数(n
类型,吸收一个凭据表)。
这个函数只起声明函数的作用,并不会输出任何内容。
接下来,使用了\my_funa:nn
函数,它会按如下方式传递参数:
将 { Hello World! }
传递给第一个参数(n
类型,#1
);将 { ~ }
传递给第二个参数(n
类型,#2
)。
这个函数将输出HelloWorld! HelloWorld!
。(原理见下一节)
最后,还直接使用了{ Hello World! }
,它和 LaTeX2e 一样,直接输出HelloWorld!
。
上面三个命令的的最终输出结果为:HelloWorld! HelloWorld!HelloWorld!
。请注意,第2个感叹号后面是没有空白的。
从上面两个函数的使用中可以看出,
N
类型参数会吸收一个凭据(不被{}
包裹的单个内容);n
类型参数会吸收一个凭据表(由{}
包裹的多个内容)。
这里大概理解就行,后面会有更精确的定义。
2.4 定义新的函数
如前面所介绍的,\cs_new:Npn
函数用于定义新的函数。\cs_new:Npn
函数有三个参数:
参数1:用于指定新函数的名称;
在本例中,它定义的函数名为\my_funa:nn
,这个函数名中的签名为nn
,表示这个新函数将接收两个参数,且参数类型均为凭据表。
参数2:用于指定新函数使用的参数列表;
在本例中,新的函数的使用的参数为#1#2
,表明这个新函数接收的两个参数分别用#1
和#2
表示。
参数3:用于指定新函数的函数体(它的内容就是前面讲的置换文本)。
在本例中,函数体为{ #1 #2 #1 }
,表明函数将被替换为“由参数2分隔的两个参数1”。即由{ ~ }
分隔的两个{ Hello World! }
。
前面讲到,空白会被忽略,所以输出结果中HelloWorld!
不会有任何空白,而它们之间会有一个空白(由~
产生)。所以最终生成HelloWorld! HelloWorld!
。
2.5 定义新函数时推断参数列表
由于函数名本身指示了其使用的参数,因此可以推断出其使用的参数。所以可以考虑省略参数列表。
为此,expl3 提供了\cs_new:Nn
函数,它与\cs_new:Npn
函数类似,但它只接收两个参数:
用于指定新函数的名称; 用于指定新函数的函数体。
2.6 定义无参函数
对于无参函数,其参数限定符应为空(但:
不应省略)。除了不使用参数外,其余规则与有参函数一样。
2.7 【补更】LaTeX3 函数与 LaTeX2e 函数(命令)
在 LaTeX3 中,定义函数时要考虑新函数的目标用户:
如果函数是给LaTeX3用户使用,则函数名应当遵守 LaTeX3 的命名规则,即上篇所介绍的规则; 如果函数是给LaTeX2e用户使用,则函数名应当遵守 LaTeX2e的命名规则(以便在LaTeX2e环境中直接使用)。
注:
除特别注明外,本教程介绍的定义函数的方法都是 LaTeX3 函数。 \cs_new:Npn 函数可以用于定义 LaTeX2e 命令,即其第一个参数可以不遵守L3命名规则。但推荐使用后面介绍的 \NewDocumentCommand 等命令来创建 LaTeX2e 命令。 上一小节所讲,无参函数的":"不能省略仅针对 LaTeX3 函数。 定义函数的方法还很多,这些将在后续的内容介绍。
选自:https://zhuanlan.zhihu.com/p/10992221850
成为 LaTeX 会员,尽享精致科研!
开通 LaTeX VIP 地址:
https://www.latexstudio.net/index/recharge/choice.html