我是 LaTeX 编程的新手,所以请耐心等待。:-)
我正在编写一个.sty
文件,我想在其中包含一个命令\dan
,该命令会根据使用零个、一个还是两个参数调用而重载三个不同的版本。
例如我想要:
\dan
生成
全英语
\dan{streaky}
或者
\dan{back}
生成
五花肉
或者
背部培根
分别和
\dan{streaky}{fried}
生成
五花熏肉配煎蛋。
“五花肉”、“油炸”等只是例子,用户应该能够输入任何争论。
我查看了该xparse
软件包,但发现文档难以理解。您能建议如何编码吗?
答案1
就是这样。
\documentclass[a4paper]{article}
\usepackage{xparse}
\NewDocumentCommand{\dan}{gg}
{\IfNoValueTF{#2}
{\IfNoValueTF{#1}
{Full English}
{#1 Bacon}%
}
{#1 Bacon with #2 Eggs}%
}
\begin{document}
\dan
\dan{streaky}
\dan{back}
\dan{streaky}{fried}
\end{document}
话虽如此,我还是建议你不要这样做。你的软件包的用户将很难弄清楚如何使用命令。只需更改参数说明符{oo}
而不是{gg}
语法,就会更符合 LaTeX 惯例:
\dan
\dan[streaky]
\dan[back]
\dan[streaky][fried]
如果您能更精确地表达您的意图,可能会建议采用不同的策略。
答案2
正如评论中所述,我建议使用更传统的 LaTeX 语法。@egreg 给出了 LaTeX3 版本,因此这里使用 LaTeX2e 中的循环:
\documentclass{article}
\makeatletter
\newcommand\dan[1][full]{%
\def\dansep{\def\dansep{, }}%
\@for\x:=#1\do{%
\dansep
\@nameuse{dan:\x}}}
\@namedef{dan:full}{Full English}
\@namedef{dan:streaky}{Streaky Bacon}
\@namedef{dan:back}{Back Bacon}
\@namedef{dan:fried}{Fried Egg}
\@namedef{dan:mushrooms}{Grilled Mushrooms}
\makeatother
\begin{document}
a \dan
b \dan[streaky]
c \dan[back]
e \dan[streaky,fried]
f \dan[streaky,fried,mushrooms]
\end{document}
答案3
正如评论中所述,使用键值接口更为可取,而 David Carlisle 给出的答案给出了传统的 LaTeX2e 方式。对于更复杂的包,我会倾向于使用 PGF 样式的键。即使没有在这个网站上询问有关 TikZ 的问题的用户数量,也表明有大量用户熟悉 PGF 样式的键值接口。
\documentclass{article}
\usepackage[latin]{babel}
\usepackage{pgfkeys}
\begin{document}
%% Step one define family
\pgfkeys{/bacon/.is family}
%% Define your keys
\pgfkeys{/bacon
type/.store in=\type,
type/.default=streaky,
cook/.store in=\cook,
cook/.default=fried
}
%% Process keys and set defaults, for later use
\def\setdefaults{\pgfkeys{/bacon
type,cook
}%
}
%
\setdefaults
\newcommand{\dan}[2][]{%
\setdefaults
\pgfkeys{/bacon #1}
\def\baconfoods{
\type\ cook \cook,
}
\baconfoods
}
\dan[type=shoulder bacon, cook=well]{}
\dan[type=streaky,cook]{}
\dan[type=streaky]{}
\dan{}
\end{document}
采用这种方法您可以获得极大的灵活性。
答案4
这是一个使用的解决方案期权包裹:
\documentclass{article}
\usepackage{catoptions}
\makeatletter
\newcommand*\dan[1][full]{%
\def\do##1{%
\ifnum\indrisnr>\@ne
,\space\iflastindris and\space\fi
\fi
\uselivecsn{dan:##1}%
}%
\indrisloop{#1}\do
}
% Default inner list parser = , (comma)
% Default outer list parser = ; (semicolon)
\newcommand*\setupdan[2][,;]{%
\def\reserved@a##1##2##3\@nil{%
\def\do####1##1####2##1####3\@nil{%
\csn@edef{dan:\cpttrimspace{####1}}{\cpttrimspace{####2}}%
}%
\def\csv@do####1{\do####1##1##1\@nil}%
\csv@@parse[##2]{#2}%
}%
\reserved@a#1,;\@nil
}
\makeatother
% Example:
\setupdan{%
full, Full English;
streaky, Streaky Bacon;
back, Back Bacon;
fried, Fried Egg;
mushrooms, Grilled Mushrooms
}
\commentBegin
% The following is also possible:
\setupdan[=,]{%
full =Full English,
streaky =Streaky Bacon,
back =Back Bacon,
fried =Fried Egg,
mushrooms =Grilled Mushrooms
}
\commentEnd
\begin{document}
\begin{enumerate}
\item\dan
\item\dan[streaky]
\item\dan[back]
\item\dan[streaky, fried]
\item\dan[streaky, fried, mushrooms]
%\item\dan[xstreaky] % error: undefined
\end{enumerate}
\end{document}