我有一个逗号分隔的key=value
字符串列表。我想根据键提取值。有点像
\LookUpValue{c}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
目的是生成字符串baz
。
我怎样才能做到这一点?
答案1
您可以定义自定义的键值解析器(假设键集应该是可变的):
\documentclass{article}
\makeatletter
\def\LookUpValue#1#2#3{%
\@tempswafalse
\gdef\LookUpValue@false{#3}%
\xdef\@tempa{#1}%
\LookUpValue@#2,\@end,}
\def\LookUpValue@#1,{%
\ifx#1\@end
\if@tempswa\@tempc\else\LookUpValue@false\fi
\else
\LookUpValue@@#1\@nil\expandafter\LookUpValue@\fi}
\def\LookUpValue@@#1=#2\@nil{%
\edef\@tempb{#1}%
\ifx\@tempa\@tempb\gdef\@tempc{#2}\@tempswatrue\fi
}
\makeatother
\begin{document}
\LookUpValue{c}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\textit{\LookUpValue{d}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}}
\LookUpValue{e}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\end{document}
附录一
如果您查看@egreg的答案,您会发现一个非常好的功能,它允许您将结果存储\LookUpValue
到宏中而不打印它。以下是在LaTeX2e中实现此目的的一种方法(给出了我的主要解决方案):
\documentclass{article}
\makeatletter
\def\LookUpValue{\kernel@ifnextchar[\@LookUpValue{\@LookUpValue[\@tempa]}}
\def\@LookUpValue[#1]#2#3{%
\@tempswafalse
\begingroup
\escapechar\m@ne
\xdef\luv@namespace{\string#1}%
\endgroup
\xdef\reserved@a{#2}%
\expandafter\LookUpValue@#3,\@end,}
\def\LookUpValue@#1,{%
\ifx#1\@end
\if@tempswa\@nameuse{@tempa}\let\@tempa\relax
\expandafter\expandafter\expandafter\@gobble\fi%
\else
\LookUpValue@@#1\@nil\expandafter\LookUpValue@\fi}
\def\LookUpValue@@#1=#2\@nil{%
\edef\reserved@b{#1}%
\ifx\reserved@a\reserved@b\@namedef{\luv@namespace}{#2}\@tempswatrue\fi
}
\makeatother
\begin{document}
\LookUpValue{c}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\def\mypreset{a=foo,b=bar,c=baz,d=zyyzx}
\LookUpValue[\myval]{d}{\mypreset}{}
\LookUpValue{e}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\textsc{\myval}
\end{document}
附录二
但是,如果您尝试提取的键值集在整个文档中是固定的,那么还有这种更简单的方法:
\documentclass{article}
\usepackage{keyval}
\makeatletter
\newcommand\newspraffkey[1]{\define@key{spraffkeys}{#1}{\@namedef{value_of_#1}{##1}}}
\newcommand\LookUpValue[2]{%
\begingroup
\setkeys{spraffkeys}{#2}%
\@nameuse{value_of_#1}%
\expandafter\ifx\csname value_of_#1\endcsname\relax\else\expandafter\@gobbleaftergroup\fi
\endgroup
}
\def\@gobbleaftergroup{\aftergroup\@gobble}
\makeatother
\newspraffkey{a}
\newspraffkey{b}
\newspraffkey{c}
\newspraffkey{d}
\begin{document}
\LookUpValue{c}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\LookUpValue{d}{a=foo,b=bar,c=baz}{error:notfound}
\LookUpValue{e}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\end{document}
答案2
property
使用语法填充列表expl3
并查找相关键值对的版本。也许不是最快的方法,但相当容易使用。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_generate_variant:Nn \prop_put:Nnn {Nxn,Nxx}
\NewDocumentCommand{\LookUpValue}{mmm}{%
\seq_set_from_clist:Nn \l_tmpa_seq {#2}
\seq_map_inline:Nn \l_tmpa_seq {% Mapping through the sequence
\seq_set_split:Nnn \l_tmpb_seq {=} {##1}
% Filling the property list
\prop_put:Nxx \l_tmpa_prop {\seq_item:Nn \l_tmpb_seq {1}} {\seq_item:Nn \l_tmpb_seq {2}}
}
% Look if #1 is in the property list and display the value, otherwise #3
\prop_if_in:NnTF \l_tmpa_prop {#1} {\prop_item:Nn \l_tmpa_prop {#1}} {#3}
}
\ExplSyntaxOff
\begin{document}
\LookUpValue{c}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\LookUpValue{foobar}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\end{document}
答案3
下面的代码使用了中的键值函数expl3
;这里我利用了“未知键”,如果事先知道键,可以做得更好。
如果给出了可选参数,它应该是一个将被(重新)定义为结果的控制序列。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\LookUpValue}{ommm}
{
\str_set:Nn \l_spraff_given_key_str { #2 }
\tl_clear:N \l_spraff_output_tl
\keys_set:nn { spraff/random } { #3 }
\tl_if_empty:NT \l_spraff_output_tl
{
\tl_set:Nn \l_spraff_output_tl { #4 }
}
\IfNoValueTF{#1}
{ \tl_use:N \l_spraff_output_tl }
{ \tl_set_eq:NN #1 \l_spraff_output_tl }
}
\keys_define:nn { spraff/random }
{
unknown .code:n =
\str_if_eq:NNT \l_spraff_given_key_str \l_keys_key_tl
{
\tl_set:Nn \l_spraff_output_tl { #1 }
}
}
\ExplSyntaxOff
\begin{document}
\LookUpValue{c}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\LookUpValue{e}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\LookUpValue[\temp]{a}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}
\texttt{\meaning\temp}
\end{document}