4

I have a comma-separated list of key=value strings. I want to extract the value based on the key. Something a bit like

\LookUpValue{c}{a=foo,b=bar,c=baz,d=zyyzx}{error:notfound}

The intention is that this would result in the string baz.

How can I do this?

4

You could define a custom key-value parser (assuming that the set of keys should be variable):

\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}

output

Addendum I

If you have a look at the answer of @egreg there is this very nice feature that allows you to store the result of \LookUpValue into a macro without printing it. Here is a way to achieve this in LaTeX2e (given my main solution):

\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}

Addendum II

However, if the set of keys which values you try to extract is fixed throughout your document there is this simpler way:

\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}
1

A version with filling up a property list using expl3 syntax and looking for the relevant key-value -pair. Perhaps not the fastest way, but quite easy to use.

\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}

enter image description here

1

The following code uses the key-value functions in expl3; here I exploit “unknown keys”, something better can be done if the keys are known in advance.

If an optional argument is given, it should be a control sequence that will be (re)defined to the result.

\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}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.