我尝试使用如下命令来制作 pgfkeys(或其他 keystyle 参数包)的一个非常简单的示例:
\mycommand{title="The new book", author="John Doe"}
得到这样的行为:
作家约翰·多伊
标题 新书
并且,如果缺少某个键,则该行可能不会出现。例如,命令
\mycommand{title="The new book"}
仅会打印:
标题 新书
我检查了网络和 StackExchange,但我只发现了非常复杂的例子,其中包括很多与键值语法不直接相关的其他内容。
那么,我怎样才能输入这样最小的键值命令呢?
答案1
我不确定你真正需要什么。这可以作为开始...
分配给title
或author
实际上运行在中定义的代码pgfkeys
。不存储任何内容。
\documentclass{article}
\usepackage{pgfkeys}
\pgfkeys{
/bibliography/.cd, % family
title/.code = {\ifx#1\empty A\else{\textbf{Title} #1\par}\fi},
author/.code = {\ifx#1\empty A\else{\textbf{Author} #1\par}\fi},
}
\newcommand{\mycommand}[1]{
\pgfkeys{
/bibliography/.cd,
#1,
}
\pgfkeysvalueof{/bibliography/title}
\pgfkeysvalueof{/bibliography/author}
}
\begin{document}
One:\par
\mycommand{title = {Tikz \& PGF}, author={JD}}
Two:\par
\mycommand{author={JD}}
Three:\par
\mycommand{title = {Tikz \& PGF}}
Four:\par
\mycommand{}
Five:\par
\mycommand{title=, author=}
\end{document}
编辑
请注意,是.code
在“参数时间”执行的,因此\mycommand{author={JD}, title = {Tikz \& PGF}}
会在标题之前打印作者。
编辑2
此版本使用\bibtitle
和\bibauthor
来存储数据。由于这些宏是全局的,因此您必须在每次调用时清除它们(设置为空),否则会记住以前的值。
\documentclass{article}
\usepackage{pgfkeys}
\pgfkeys{
/bibliography/.cd, % family
title/.store in = \bibtitle,
author/.store in = \bibauthor,
}
\newcommand{\mycommand}[1]{
\pgfkeys{
/bibliography/.cd,
title = {}, % clear title
author = {}, % clear author
#1,
}
\ifx\bibtitle\empty\else\textbf{Title:} \bibtitle\par\fi
\ifx\bibauthor\empty\else\textbf{Author:} \bibauthor\par\fi
}
\begin{document}
One:\par
\mycommand{title = {Tikz \& PGF}, author={JD}}
\mycommand{author={JD}, title = {Tikz \& PGF}}
\vspace{2ex}
Two:\par
\mycommand{author={JD}}
\vspace{2ex}
Three:\par
\mycommand{title = {Tikz \& PGF}}
\vspace{2ex}
Four:\par
\mycommand{}
\vspace{2ex}
Five:\par
\mycommand{title=, author=}
\end{document}
答案2
这是一个带有键的实现expl3
。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% define the keys
\keys_define:nn { fauve/books }
{
title .tl_set:N = \l__fauve_books_title_tl, % the title
author .tl_set:N = \l__fauve_books_author_tl, % the author
}
% formatting
\NewDocumentCommand{\mycommand}{m}
{
\group_begin:
\keys_set:nn { fauve/books } { #1 } % populate the keys
% format the book
\par\addvspace{\topsep}
\fauve_books_author:V \l__fauve_books_author_tl
\fauve_books_title:V \l__fauve_books_title_tl
\par\addvspace{\topsep}
\group_end:
}
\cs_new_protected:Nn \fauve_books_title:n
{
\tl_if_empty:nF { #1 }
{
\par\noindent\textbf{Title:}~#1
}
}
\cs_new_protected:Nn \fauve_books_author:n
{
\tl_if_empty:nF { #1 }
{
\par\noindent\textbf{Writer:}~#1
}
}
\cs_generate_variant:Nn \fauve_books_title:n {V}
\cs_generate_variant:Nn \fauve_books_author:n {V}
\ExplSyntaxOff
\begin{document}
\mycommand{title=The new book, author=John Doe}
\mycommand{title=Another book}
\end{document}
我已经分离了每个键特定的格式化命令,但这是可选的。
答案3
无论如何,我将展示如何在 ConTeXt 中编写这样的宏。ConTeXt 有几个键值驱动接口,但对于像这样简单的东西,我只需借助\setupvariables[...][..=..]
和\getvariable{...}{...}
。
\unprotect
\define\mycommand
{\dosingleargument\mycommand_setup}
\def\mycommand_setup[#1]%
{\bgroup
\setvariables[mycommand][#1]%
\mycommand_process
\egroup}
\def\mycommand_process
{\startlines
\doifsomething{\getvariable{mycommand}{author}}
{\bold{Writer:} \getvariable{mycommand}{author}\endgraf}%
\doifsomething{\getvariable{mycommand}{title}}
{\bold{Title:} \getvariable{mycommand}{title}}%
\stoplines}
\protect
\starttext
\mycommand[title={The new book}, author={John Doe}]
\mycommand[title={The new book}]
\stoptext
请注意,我修改了界面(使用\mycommand[...]
而不是\mycommand{...}
)以符合 ConTeXt 约定,即方括号中的参数用于选项,大括号中的参数用于排版的文本。
答案4
使用expkv-cs
最少的 key=value 宏非常容易实现。
在这种情况下,我们可能还希望在给定或不给定键的情况下有不同的行为。这可以通过一个间接级别相对容易地实现,其中第一级包含默认值(如果未提供任何内容),第二级添加标记/格式化指令(如果使用了键)。这样,我们不需要在宏替换中进行任何测试,但可以直接使用这些值(即使它们是空的)。为此,以下使用-internal
真正的键,但添加包装器来添加类似\par\noindent
或类似的东西。
\documentclass[]{article}
\usepackage{expkv-cs}
% declaring the internal keys and the order of output.
\ekvcSplit\mycommand
{
% long since it'll get a `\par` token by the frontend key
long author-internal = {} % #1
, title-internal = \emph{No title} % #2
,long year-internal = {} % #3
}
{#1\par\noindent#2#3}
% Declaring the front level keys and how they interact with the internal keys.
% A meta key will set other keys, so if `year=YYYY` is called it'll be
% equivalent to `year-internal=\par\noindent\textbf{Year} YYYY`
\ekvcSecondaryKeys\mycommand
{
% for a single key=value pair set by a `meta` secondary key we don't need
% additional braces guarding the second = in expkv. The following is
% equivalent to
% meta author = {author-internal = {\par\noindent\textbf{Writer} #1}}
meta author = author-internal = {\par\noindent\textbf{Writer} #1}
,meta title = title-internal = {\textbf{Title} #1}
,meta year = year-internal = {\par\noindent\textbf{Year} #1}
}
\begin{document}
\mycommand{title=The new book,author=John Doe}
\bigskip
\mycommand{title=The new book}
\bigskip
\mycommand{title=The new book,year=2020}
\bigskip
\mycommand{author=John Doe,year=2020}
\end{document}