![有没有办法向命令添加可选和/或命名参数](https://linux22.com/image/468000/%E6%9C%89%E6%B2%A1%E6%9C%89%E5%8A%9E%E6%B3%95%E5%90%91%E5%91%BD%E4%BB%A4%E6%B7%BB%E5%8A%A0%E5%8F%AF%E9%80%89%E5%92%8C%2F%E6%88%96%E5%91%BD%E5%90%8D%E5%8F%82%E6%95%B0.png)
我正在为我的学生编写一本手册,我想创建一个命令,该命令应该绘制任务定义、其类型和可能的特征,例如来源和指向 YouTube 上的解决方案的链接。
在我的计划中,所有这些定义都应该起作用(当然,我在这里故意使用伪语法,只是为了向你展示我的意图):
\task{definition=$x=3$}
\task{definition=$x=3$, source='ABC'}
\task{definition=$x=3$, link='https://youtube.ru'}
\task{definition=$x=3$, source='ABC', link='https://youtube.ru'}
但我找不到任何类似于可选和命名参数的工具。
答案1
传统的 LaTeX2e 解决方案是keyval
包(由 所使用\includegraphics[height=2cm, scale=3]{...}
),但最近的 LaTeX 版本包含一个基于 的内置 keyval 解析器l3keys
。
@Campa 的示例经过修改以使用较新的系统:
\documentclass{article}
\makeatletter
\DeclareKeys[task]{
definition .store = \task@definition,
source .store = \task@source,
link .store = \task@link
}
\NewDocumentCommand\task{m}{%
\begingroup
\SetKeys[task]{#1}%
This is a task with definition \task@definition.%
\ifx\task@source\@empty\else\space You can find its source in \task@source.\fi
\ifx\task@link\@empty\else\space (See \task@link)\fi
\endgroup
}
\makeatother
\begin{document}
\parindent0pt
\task{definition={$x=3$}}\par % you must "hide" the =
\task{definition={$x=3$}, source=ABC}\par
\task{definition={$x=3$}, link=https://youtube.ru}\par
\task{definition={$x=3$}, source=ABC, link=https://youtube.ru}
\task{definition={$x=3$}} % you must "hide" the =
\end{document}
答案2
这可能是开始使用keyval
\documentclass{article}
\usepackage{keyval}
\makeatletter
\newcommand*{\task@definition}{}
\newcommand*{\task@source}{}
\newcommand*{\task@link}{}
\define@key{task}{definition}{\def\task@definition{#1}}
\define@key{task}{source}{\def\task@source{#1}}
\define@key{task}{link}{\def\task@link{#1}}
\newcommand*{\task}[1]{%
\begingroup
\setkeys{task}{#1}%
This is a task with definition \task@definition.%
\ifx\task@source\@empty\else\space You can find its source in \task@source.\fi
\ifx\task@link\@empty\else\space (See \task@link)\fi
\endgroup
}
\makeatother
\begin{document}
\parindent0pt
\task{definition={$x=3$}}\par % you must "hide" the =
\task{definition={$x=3$}, source=ABC}\par
\task{definition={$x=3$}, link=https://youtube.ru}\par
\task{definition={$x=3$}, source=ABC, link=https://youtube.ru}
\task{definition={$x=3$}} % you must "hide" the =
\end{document}
答案3
对于一个简单的任务,在我看来1expkv-cs
,没有什么比和的简单性更好\ekvcSplit
(这只适用于最多 9 个键,对于更多键,最好使用expkv-def
类似于\DeclareKeys
-- 的方法或另一个 key=value 实现,如 LaTeX 内置的实现)。
1我是《和家人》的作者expkv
。
为了能够轻松地向键添加格式说明和额外文本,可以使用装饰某些内部键的正面键。因此每次您说link = www.example.com
这句话时都会变成link-internal={ (See www.example.com)}
。
另外,expkv
您不必隐藏额外的=
,但您必须隐藏一个,
。
这借用了@campa 创建的示例并对其进行了修改以使用expkv-cs
:
\documentclass{article}
\usepackage{expkv-cs}
\ekvcSplit\task
{
% set up primary keys, all defaulting to an empty value
definition = {}
,source-internal = {}
,link-internal = {}
}
{This is a task with definition #1.#2#3}
% set up decorators
\ekvcSecondaryKeys\task
{
meta source = {source-internal = { You can find its source in #1.}}
,meta link = {link-internal = { (See #1)}}
}
\begin{document}
\parindent0pt
\task{definition=$x=3$}\par
\task{definition=$x=3$, source=ABC}\par
\task{definition=$x=3$, link=https://youtube.ru}\par
\task{definition=$x=3$, source=ABC, link=https://youtube.ru}
\task{definition=$x=3$}
\end{document}
除了版本之外\ekvcSplit
,您还可以使用版本\ekvcHash
,其中您可以通过名称访问键值(整个列表将在内部转发#1
,\ekvcValue
并可用于访问该列表中的项目 - 这适用于任意多个键)。
\documentclass{article}
\usepackage{expkv-cs}
\ekvcHash\task
{
% set up primary keys, all defaulting to an empty value
definition = {}
,source-internal = {}
,link-internal = {}
}
{%
This is a task with definition \ekvcValue{definition}{#1}.%
\ekvcValue{source-internal}{#1}%
\ekvcValue{link-internal}{#1}%
}
% set up decorators
\ekvcSecondaryKeys\task
{
meta source = {source-internal = { You can find its source in #1.}}
,meta link = {link-internal = { (See #1)}}
}
\begin{document}
\parindent0pt
\task{definition=$x=3$}\par
\task{definition=$x=3$, source=ABC}\par
\task{definition=$x=3$, link=https://youtube.ru}\par
\task{definition=$x=3$, source=ABC, link=https://youtube.ru}
\task{definition=$x=3$}
\end{document}
如果您想要一个更接近于 提供的接口,\DeclareKeys
您可以使用expkv-def
。除了store
-handler 之外,它还提供dataT
。指令dataT link = \taskLink
将定义\taskLink
这样一种方式,即默认情况下它将吞噬下一个标记或大括号组,但如果使用了键,它将把值放在{<value>}
下一个标记或大括号组的后面(并从后面的大括号组中剥离大括号)。
\documentclass{article}
\usepackage{expkv-def}
\ekvdefinekeys{task}
{
store definition = \taskDefinition
,dataT source = \taskSource
,dataT link = \taskLink
}
\newcommand\taskSourceFormatter[1]{ You can find its source in #1.}
\newcommand\taskLinkFormatter[1]{ (See #1)}
\newcommand\task[1]
{%
\begingroup
\ekvset{task}{#1}%
This is a task with definition \taskDefinition.%
\taskSource\taskSourceFormatter
\taskLink\taskLinkFormatter
\endgroup
}
\begin{document}
\parindent0pt
\task{definition=$x=3$}\par
\task{definition=$x=3$, source=ABC}\par
\task{definition=$x=3$, link=https://youtube.ru}\par
\task{definition=$x=3$, source=ABC, link=https://youtube.ru}
\task{definition=$x=3$}
\end{document}
如果您确实想要,那么您可以使用与keyval
使用基本包基本相同的语法,expkv
而无需任何扩展包:
\documentclass{article}
\usepackage{expkv}
\newcommand*\taskDefinition{}
\newcommand*\taskSource{}
\newcommand*\taskLink{}
\ekvdef{task}{definition}{\def\taskDefinition{#1}}
\ekvdef{task}{source}{\def\taskSource{#1}}
\ekvdef{task}{link}{\def\taskLink{#1}}
\newcommand\task[1]
{%
\begingroup
\ekvset{task}{#1}%
This is a task with definition \taskDefinition.%
\ifx\taskSource\empty\else\space You can find its source in \taskSource.\fi
\ifx\taskLink\empty\else\space (See \taskLink)\fi
\endgroup
}
\begin{document}
\parindent0pt
\task{definition=$x=3$}\par
\task{definition=$x=3$, source=ABC}\par
\task{definition=$x=3$, link=https://youtube.ru}\par
\task{definition=$x=3$, source=ABC, link=https://youtube.ru}
\task{definition=$x=3$}
\end{document}
所有代码块的结果: