![xparse:如何使用复杂的参数规范包装文档命令?](https://linux22.com/image/354345/xparse%EF%BC%9A%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E5%A4%8D%E6%9D%82%E7%9A%84%E5%8F%82%E6%95%B0%E8%A7%84%E8%8C%83%E5%8C%85%E8%A3%85%E6%96%87%E6%A1%A3%E5%91%BD%E4%BB%A4%EF%BC%9F.png)
假设我有一个具有复杂参数规范的函数,如下所示:
\DeclareDocumentCommand\backend{m moomm}{
Type: #1, arguments: #2 #3 #4 #5 #6
}
我想声明一组包装器,为第一个参数插入一些内容,但保留其余参数不变(将它们传递给命令\backend
),如下所示:
\DeclareDocumentCommand\typeA{moomm}{%
\backend{A}{#1}[#2][#3]{#4}{#5}%
}
这似乎有效,但这真的是一种适用于所有类型参数的“安全”方法吗?或者这更好:
\def\typeB{\backend{B}}
或者两者等同?什么是最佳实践?
这里有一个 MWE 可以玩一下:
\documentclass{article}
\usepackage{xparse}
\DeclareDocumentCommand\backend{m moomm}{
Type: #1, arguments: #2 #3 #4 #5 #6
}
\DeclareDocumentCommand\typeA{moomm}{%
\backend{A}{#1}[#2][#3]{#4}{#5}%
}
\def\typeB{\backend{B}}
\begin{document}
\typeA{Foo}[opt.]{m2}{m3}
\typeB{Bar}[opt.]{m2}{m3}
\end{document}
答案1
像这样吗?
\NewDocumentCommand
除非\DeclareDocumentCommand
您确定要覆盖任何现有命令,但通常情况并非如此。
基本思想是,xparse
函数只是包装器,用于处理用户输入、调用适当的低级函数并适当地传递任何参数值。因此,在这种情况下,我们需要 3 个低级函数:分别用于 4、5 和 6 个参数。或者,如果您确实希望在未指定选项时使用默认值,则只需要一个低级函数,代码更简单。
假设更复杂的情况,每个xparse
宏只需决定指定多少个参数并将相关值传递给适当的低级命令。
\cs_new_protected_nopar
如果您确定要使用,则可以使用m
而不是+m
和o
而不是+o
作为参数规范。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Nn \latechneuse_backend:nnnnnn
{
Type: ~ #1, ~ arguments: ~ #2 ~ #3 ~ #4 ~ #5 ~ #6
}
\cs_new_protected:Nn \latechneuse_backend:nnnnn
{
Type: ~ #1, ~ arguments: ~ #2 ~ #3 ~ #4 ~ #5
}
\cs_new_protected:Nn \latechneuse_backend:nnnn
{
Type: ~ #1, ~ arguments: ~ #2 ~ #3 ~ #4
}
\NewDocumentCommand \backend { mmoomm }
{
\group_begin:
\IfValueTF { #3 }
{
\IfValueTF { #4 }
{
\latechneuse_backend:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 }
}{
\latechneuse_backend:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 }
}
}{
\latechneuse_backend:nnnn { #1 } { #2 } { #3 } { #4 }
}
\group_end:
}
\NewDocumentCommand \altbackend { m m O {default} O {default} m m }
{
\group_begin:
\latechneuse_backend:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 }
\group_end:
}
\NewDocumentCommand \typeA { m o o m m }
{
\group_begin:
\IfValueTF { #2 }
{
\IfValueTF { #3 }
{
\latechneuse_backend:nnnnnn { A } { #1 } { #2 } { #3 } { #4 } { #5 }
}{
\latechneuse_backend:nnnnn { A } { #1 } { #2 } { #4 } { #5 }
}
}{
\latechneuse_backend:nnnn { A } { #1 } { #4 } { #5 }
}
\group_end:
}
\NewDocumentCommand \typeB { m o o m m }
{
\group_begin:
\IfValueTF { #2 }
{
\IfValueTF { #3 }
{
\latechneuse_backend:nnnnnn { B } { #1 } { #2 } { #3 } { #4 } { #5 }
}{
\latechneuse_backend:nnnnn { B } { #1 } { #2 } { #4 } { #5 }
}
}{
\latechneuse_backend:nnnn { B } { #1 } { #4 } { #5 }
}
\group_end:
}
\NewDocumentCommand \alttypeA { m O {default} O {default} m m }
{
\group_begin:
\latechneuse_backend:nnnnnn { A } { #1 } { #2 } { #3 } { #4 } { #5 }
\group_end:
}
\NewDocumentCommand \alttypeB { m O {default} O {default} m m }
{
\group_begin:
\latechneuse_backend:nnnnnn { B } { #1 } { #2 } { #3 } { #4 } { #5 }
\group_end:
}
\ExplSyntaxOff
\begin{document}
\typeA{Foo}[opt.]{m2}{m3}
\typeB{Bar}[opt.]{m2}{m3}
\end{document}
很难想象这个界面真的是一个很好的设计选择,但如果没有更多有关实际用例的信息,就不可能说出如何以不同的方式实现它。(可能是键值接口,但正如我所说,仅凭这么少的信息就无法真正说出。)