
У меня есть список 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}
Приложение I
Если вы посмотрите на ответ @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}
Приложение II
Однако, если набор ключей, значения которых вы пытаетесь извлечь, фиксирован во всем документе, есть более простой способ:
\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}