在过去的几天里,我一直在努力实现以下目标,但无法找到解决方案。
我有以下最小工作示例:
\documentclass{article}
\usepackage{xkeyval}
\usepackage{amssymb, amsmath}
\usepackage{xparse}
\usepackage{etoolbox}
\makeatletter
\define@cmdkey [Notation] {nom} {A} {}
\define@cmdkey [Notation] {nom} {B} {}
\presetkeys [Notation] {nom} {A={},B={}}{}
\NewDocumentCommand{\nom}{ m O{} }{%
\setkeys[Notation]{nom}{#2}%
\ifdefempty{\cmdNotation@nom@A}{% Descriptor section
\ifdefempty{\cmdNotation@nom@B}{%
e-\def\subscript{}
}{%
f-\def\subscript{\mathtt{\cmdNotation@nom@B}}%
}%
}{%
\ifdefempty{\cmdNotation@nom@B}{%
g-\def\subscript{\mathtt{\cmdNotation@nom@A}}%
}{%
h-\def\subscript{\mathtt{\cmdNotation@nom@A,\cmdNotation@nom@B}}%
}%
}%
\mathcal{#1}_{\subscript}
}%
\makeatother
\makeatletter
\define@cmdkey [Notation] {test} {of} {}
\define@cmdkey [Notation] {test} {wrt} {}
\presetkeys [Notation] {test} {of={},wrt={}}{}
\NewDocumentCommand{\test}{ m O{} }{%
\setkeys[Notation]{test}{#2}%
\nom{#1}[A=\cmdNotation@test@of, B=\cmdNotation@test@wrt]
}%
\makeatother
\begin{document}
\begin{align}
\nom{K}[A=A, B=B]\\
\nom{K}[A=A] \\
\nom{K}[B=B] \\
\nom{K} \\
\test{K}[of=A, wrt=B] \\
\test{K}[of=A] \\
\test{K}[wrt=B] \\
\test{K}
\end{align}
\end{document}
基本上,当我在 \test 内部调用 \nom 并且 test 的可选输入为空时,它们会在 \nom 中作为非空参数接收。
到目前为止,我发现的唯一解决方案如下:
\makeatletter
\define@cmdkey [Notation] {test} {of} {}
\define@cmdkey [Notation] {test} {wrt} {}
\presetkeys [Notation] {test} {of={},wrt={}}{}
\NewDocumentCommand{\test}{ m O{} }{%
\setkeys[Notation]{test}{#2}%
\ifdefempty{\cmdNotation@test@wrt}{%
\ifdefempty{\cmdNotation@test@of}{%
\nom{#1}[]
}{%
\nom{#1}[B=\cmdNotation@test@of]
}%
}{%
\ifdefempty{\cmdNotation@test@of}{%
\nom{#1}[A=\cmdNotation@test@wrt]
}{%
\nom{#1}[A=\cmdNotation@test@wrt, B=\cmdNotation@test@of]
}%
}%
}%
\makeatother
但这是不可行的,因为在我的实际实现中,\nom 和 \test 有超过 10 个输入,我无法为每个输入组合创建检查。此外,我还有 10 个类似于 \test 的其他函数在内部调用 \nom。
希望您能帮助我。提前致谢!
编辑:
正如 @Gaussler 和 @egreg 所建议的,使用列表原则上是可行的。但我偶然发现有些情况传递的参数不是列表的一部分,或者需要另一种形式的评估而不是简单的逗号分隔(参见蓝色圆圈)。例如,第一种情况下的 \dot、\hat 是两个可选修饰符 \mod 和 \modd,或者 K 和 L 是文本描述符的一部分,其中两个/一个/没有输入可以存在。
对于每个 \test_i i = 1:n 的情况,我可以使用不同的输入组合并将它们传递给 \nom 以根据我的需要生成不同的方程式。
答案1
我不确定为什么要这样间接。无论如何,使用 expl3 做任何事情都更容易。请注意分组,这样在同一级别设置的键就不会互相影响。
该\test
命令将不是使用可选参数进行调用\nom
,因为它已经设置了选项。
\documentclass{article}
\usepackage{amssymb, amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\keys_define:nn { notation/nom }
{
A .tl_set:N = \l_wdsgn_notation_A_tl,
B .tl_set:N = \l_wdsgn_notation_B_tl,
A .initial:n = {},
B .initial:n = {},
}
\keys_define:nn { notation/test }
{
of .code:n = \keys_set:nn { notation/nom } { A=#1 },
wrt .code:n = \keys_set:nn { notation/nom } { B=#1 },
}
\NewDocumentCommand{\nom}{ m O{} }
{
\group_begin:
\wdsgn_notation_nom:nn { #1 } { #2 }
\group_end:
}
\clist_new:N \l__wdsgn_notation_subscript_clist
\cs_new:Nn \wdsgn_notation_nom:nn
{
\keys_set:nn { notation/nom } { #2 }
\tl_if_empty:NTF \l_wdsgn_notation_A_tl
{ % A is empty
\tl_if_empty:NTF \l_wdsgn_notation_B_tl { e- } { f- }
}
{ % A is not empty
\tl_if_empty:NTF \l_wdsgn_notation_B_tl { g- } { h- }
}
\mathcal{#1}
\clist_put_right:NV \l__wdsgn_notation_subscript_clist \l_wdsgn_notation_A_tl
\clist_put_right:NV \l__wdsgn_notation_subscript_clist \l_wdsgn_notation_B_tl
\clist_if_empty:NF \l__wdsgn_notation_subscript_clist
{ % here we exploit the fact that \clist_use:Nn disregards empty items
\sb{\mathtt{\clist_use:Nn \l__wdsgn_notation_subscript_clist {,}}}
}
}
\NewDocumentCommand{\test}{ m O{} }
{
\group_begin:
\keys_set:nn { notation/test } { #2 }
\nom{#1}
\group_end:
}
\ExplSyntaxOff
\begin{document}
\begin{align}
\nom{K}[A=A, B=B]\\
\nom{K}[A=A] \\
\nom{K}[B=B] \\
\nom{K} \\
\test{K}[of=A, wrt=B] \\
\test{K}[of=A] \\
\test{K}[wrt=B] \\
\test{K}
\end{align}
\end{document}
笔记。感谢高斯勒指出需要修复的问题。
答案2
因为无聊,我提出了另一种解决方案。(除此之外,请允许我评论一下,你的语法对我来说似乎非常违反直觉。你确定这真的是你想要输入的方式吗?)
\documentclass{article}
\usepackage{semantex}
\NewSymbolClass\nom[
data provide=data A,
data provide=data B,
parse options={
command=\mathcal,
inner return,
if blank TF={\SemantexDataGetExpNot{data A}}{
if blank TF={\SemantexDataGetExpNot{data B}}
{
symbol put left={e-},
}
{
symbol put left={f-},
set keys x={
sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data B}}},
},
},
}
{
if blank TF={\SemantexDataGetExpNot{data B}}
{
symbol put left={g-},
set keys x={
sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data A}}},
},
}
{
symbol put left={h-},
set keys x={
sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data A}}},
sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data B}}},
},
},
},
},
define keys[1]={
{A}{ data set={data A}{#1} },
{B}{ data set={data B}{#1} },
},
]
\NewSymbolClass\test[
parent=\nom,
define keys[1]={
{of}{ A={#1} },
{wrt}{ B={#1} },
},
]
\begin{document}
\begin{align}
\nom{K}[A=A, B=B]\\
\nom{K}[A=A] \\
\nom{K}[B=B] \\
\nom{K} \\
\test{K}[of=A, wrt=B] \\
\test{K}[of=A] \\
\test{K}[wrt=B] \\
\test{K}
\end{align}
\end{document}
我不太清楚你更新后的答案是什么意思。但semantex
也可以编程来处理这种情况。请原谅我在下面使用了奇怪的命令名称,但我不太清楚你的符号到底是什么意思:
\documentclass{article}
\usepackage{semantex}
\NewVariableClass\MyVar[
output=\MyVar,
]
% First a few variables; the "v" stands for variable:
\NewObject\MyVar\vh{h}
\NewObject\MyVar\vg{g}
\NewObject\MyVar\vf{f}
\NewObject\MyVar\ve{e}
\NewObject\MyVar\vK{K}
\NewObject\MyVar\vL{L}
% Feel free to give the following more descriptive names:
\NewObject\MyVar\guid{\mathrm{guid}} % could also use \operatorname, depending on what "guid" is
\NewObject\MyVar\scriptK{\mathcal{K}}
\NewObject\MyVar\ttA{\mathtt{A}}
\NewObject\MyVar\ttB{\mathtt{B}}
\NewObject\MyVar\ttC{\mathtt{C}}
\NewObject\MyVar\ttD{\mathtt{D}}
\NewObject\MyVar\ttE{\mathtt{E}}
\NewObject\MyVar\ttF{\mathtt{F}}
\NewObject\MyVar\ttG{\mathtt{G}}
\NewObject\MyVar\ttH{\mathtt{H}}
\NewObject\MyVar\ttX{\mathtt{X}}
\NewObject\MyVar\ttY{\mathtt{Y}}
\NewVariableClass\WeirdConstruction[
parent=\MyVar,
data provide=data A,
data provide=data B,
data provide=data C,
data provide=data D,
data provide=data E,
data provide=data F,
data provide=data G,
data provide=data H,
define keys={
{mod}{ command=\hat },
{modd}{ command=\dot },
},
define keys[1]={
{A}{ data set={data A}{#1} },
{B}{ data set={data B}{#1} },
{C}{ data set={data C}{#1} },
{D}{ data set={data D}{#1} },
{E}{ data set={data E}{#1} },
{F}{ data set={data F}{#1} },
{G}{ data set={data G}{#1} },
{H}{ data set={data H}{#1} },
{description}{
parse,
if blank TF={\SemantexDataGetExpNot{lower}}
{
lower={#1},
}
{
lower={_\bgroup #1},
post lower=\egroup,
},
},
},
parse options={
set keys x={
sep upper left=\SemantexDataGetExpNot{data B},
sep upper left=\SemantexDataGetExpNot{data A},
sep lower left=\SemantexDataGetExpNot{data D},
sep lower left=\SemantexDataGetExpNot{data C},
sep upper=\SemantexDataGetExpNot{data E},
sep upper=\SemantexDataGetExpNot{data F},
sep lower=\SemantexDataGetExpNot{data G},
sep lower=\SemantexDataGetExpNot{data H},
},
},
]
\NewObject\WeirdConstruction\ThetaConstruction{\Theta}
\NewObject\WeirdConstruction\aConstruction{\mathbf{a}}
\begin{document}
\[
\ThetaConstruction[
A=\ttA, B=\ttB,
C=\ttC, D=\ttD,
E=\ttE, F=\ttF,
G=\ttG, H=\ttH,
mod, modd,
description=\vK,
description=\vL,
]
\]
\[
\aConstruction[
A=\ttC,C=\ttX,
mod, modd,
description=\guid,
description=3,
]
\]
\end{document}