我希望能够创建一个命令(使用pgfkeys
),该命令可以接受有限形式的输入,并且某些部分将来自一组有限的值。更具体地说,任何输入都会有一些部分A
(来自已知列表),并且对于某些值A
,附加信息#1
,#2
等(不是来自已知列表)能也可以使用一组有限的形式来指定,但不必如此。
举个虚构的例子,假设我的命令是\meal
,并且A
将成为列表的一个元素
chicken, beef, tofu
当A
是chicken
或时beef
,以下形式的附加信息能可以这样指定:
chicken with #1
chicken on a bed of #1
beef with #1
beef with #1 or #2
我希望最大可能的多功能性一旦确定了正确的形式,并且理解了输入,会发生什么。例如,假设我想要
\meal{chicken} -> Chicken
\meal{chicken with #1} -> CHICKEN (with #1? uggh)
\meal{chicken on a bed of #1} -> #1, underneath chicken
\meal{beef} -> Beef
\meal{beef with #1} -> Beef and a side of #1
\meal{beef with #1 or #2} -> Beef with your choice of #1 or #2 as a side
\meal{tofu} -> Tofu
我意识到这已经是一个相当艰巨的任务了(哈哈),但为了简单起见,假设我们永远不需要写
\meal{chicken on a bed of beef with chicken}
或其他会让计算机感到困惑的东西。
现在,我正在做一些初步测试(在尝试制作一个可以完成我想要的所有事情的东西之前),然后遇到了一个问题。我写的代码,在适应这个虚构的例子之后,将是
\documentclass{article}
\usepackage{pgfkeys}
\pgfkeys{%
mealname/.initial = ,%
overform/.style args = {#1 over #2}{mealname = #1 over #2},%
andform/.style args = {#1 and #2}{mealname = #1 and #2}%
noform/.style = {mealname = #1}%
}
\newcommand{\meal}[1]{%
\pgfkeys{%
overform/.try = #1,%
andform/.retry = #1,%
noform/.retry = #1,%
mealname/.get = \mealname}%
\mealname%
}
\begin{document}
\meal{A over B}
\end{document}
运行正常;但是,当我A over B
用替换时A and B
,出现错误
File ended while scanning use of \pgfkeys@code
我假设发生的事情是,它pgfkeys
试图over
在输入中找到该单词的出现A and B
,但陷入了无限循环,或者因为找不到而以某种方式中断。我曾希望在over
任何地方都找不到后,会抛出一个错误并告知/.try
停止,但事实似乎并非如此。
现在,我意识到我所要求的可能有点愚蠢,因为那pgfkeys
是针对“键值参数”的,因为一个更容易编码(但使用起来稍微不太直观)的解决方案是让每种不同的形式(chicken
,,chicken with
等等)成为它自己的键,并接受如下输入:
\meal{chicken}
\meal{chicken with = #1}
...
或者,让 的每个值A
成为一个家族,形式为子键;例如,调用键chicken
会将/.cd
我们带入/chicken/
家族,其中有键/chicken/with
和/chicken/on a bed of
,这样就可以写
\meal{chicken}
\meal{chicken, with = #1}
...
也许我只是过于挑剔,想要避免使用等号;但在最大程度上,我希望我的文档代码能够模拟自然的英语表达(除了只是想弄清楚如何应对挑战/出于好奇)。
因此,我的问题是:有什么方法可以实现我想要的命令吗pgfkeys
? 还有其他包或方法可以做到这一点吗? 假设我的方法至少在某种程度上是正确的:有什么方法可以使用/.style args
键处理程序(也许与/.try
处理程序一起使用?)来确定输入的形式,并对该形式执行正确的操作,而不会陷入无限循环,试图测试输入是否是给定的形式?
答案1
您可以执行以下操作。
不过,这并没有检查太多。所以你可以说
\meal{Tofu with something}
而不会引发错误。
代码
\documentclass{article}
\usepackage{pgf,pgfkeys}
\makeatletter
\newcommand*{\kitchenset}{\pgfqkeys{/kitchen}}
\newcommand*{\kitchenalso}{\pgfqkeysalso{/kitchen}}
\newcommand*{\qrr@pgfutil@in@}[2]{%
\pgfutil@in@{#1}{#2}%
\ifpgfutil@in@
\expandafter\pgfutil@firstoftwo
\else
\expandafter\pgfutil@secondoftwo
\fi
}
\kitchenset{
mealname/.initial=Nothing,
mealwith/.initial=nothing,
mealwithor/.initial=nothing,
mealbed/.initial=a plate,
@meal/.code={%
\qrr@pgfutil@in@
{ with }{#1}
{\kitchenalso{@meal with={#1}}}
{%
\qrr@pgfutil@in@
{ on a bed of }{#1}
{\kitchenalso{@meal bed={#1}}}
{\kitchenalso{mealname={#1}}}%
}%
},
@meal with/.code args={#1 with #2}{%
\kitchenalso{mealname={#1}}
\qrr@pgfutil@in@
{ or }{#2}
{\kitchenalso{@meal with or={#2}}}
{\kitchenalso{mealwith={#2}}}%
},
@meal with or/.style args={#1 or #2}{%
mealwith={#1},
mealwithor={#2},
},
@meal bed/.style args={#1 on a bed of #2}{%
mealname={#1},
mealbed={#2},
}
}
\makeatother
\newcommand*{\kitchenvalues}{%
Meal: \pgfkeysvalueof{/kitchen/mealname} with \pgfkeysvalueof{/kitchen/mealwith} (or \pgfkeysvalueof{/kitchen/mealwithor}) on a bed of \pgfkeysvalueof{/kitchen/mealbed}.}
\newcommand*{\meal}[1]{%
\begingroup
\kitchenset{@meal={#1}}%
\kitchenvalues
\endgroup}
\begin{document}
\meal{xxx}
\meal{Beef}
\meal{Beef with Salad}
\meal{Beef with Salad or French Fries}
\end{document}