6

There are probably other ways to do that, but I was happy I've found this code working just fine for my needs:

\documentclass{article}
\usepackage{tikz}
\newcounter{grpcnt}
\def\groups{grp1, grp2, grp3}
\def\keyvals{{ {"key 00/val 00, key 01/val 01"}, {"key 10/val 10, key 11/val 11, key 12/val 12"}, {"key 20/val 20"} }}
\begin{document}
\setcounter{grpcnt}{0}
\foreach \grp in \groups {
    \section*{\grp}
    \pgfmathparse{\keyvals[\thegrpcnt]}
    \foreach \key/\val in \pgfmathresult
    {
        \textbf{\key}: \val \\[1ex]
    }
    \addtocounter{grpcnt}{1}
}
\end{document}

The problem I have is if I try to store any font styling in the 2nd array, say an \emph{} on the first value 00:

\documentclass{article}
\usepackage{tikz}
\newcounter{grpcnt}
\def\groups{grp1, grp2, grp3}
\def\keyvals{{ {"key 00/val \emph{00}, key 01/val 01"}, {"key 10/val 10, key 11/val 11, key 12/val 12"}, {"key 20/val 20"} }}
\begin{document}
\setcounter{grpcnt}{0}
\foreach \grp in \groups {
    \section*{\grp}
    \pgfmathparse{\keyvals[\thegrpcnt]}
    \foreach \key/\val in \pgfmathresult
    {
        \textbf{\key}: \val \\[1ex]
    }
    \addtocounter{grpcnt}{1}
}
\end{document}

Which will break compilation. I found out that some other types of commands are seen and interpreted correctly (e.g., some special characters like \AE work just fine), but any font syling command I've tried (\large, \textbf{}, \itshape, etc.) have failed. Any idea why and/or how I could store some font styling in the 2nd array? Thanks! :)

4
  • Welcome to TeX SE. This is a great first question. I don't use this feature but the problem is that TeX expects the values to be well, mathematical values not text. If you want to do something similar with text, I think you would be better off using something designed to deal with it.
    – cfr
    Commented Feb 20, 2014 at 23:46
  • As @cfr says, welcome to TeX.SX! Also, a tip: You can use backticks ` to mark your inline code as I did in my edit.
    – Adam Liter
    Commented Feb 21, 2014 at 0:04
  • @cfr: well, I will certainly try to find another way...
    – shrodi
    Commented Feb 21, 2014 at 0:14
  • from the names of your macros I would recommend switching to a key value system such as pgfkeys. ther yiu can store or manipulate things much easier.
    – percusse
    Commented Feb 21, 2014 at 9:22

2 Answers 2

4

The problem is that \pgfmathparse performs \edef and commands such as \emph don't survive it.

You get what you need by preceding such commands with \noexpand:

\documentclass{article}
\usepackage{tikz}
\newcounter{grpcnt}
\def\groups{grp1, grp2, grp3}
\def\keyvals{{ {"key 00/val \noexpand\emph{00}, key 01/val 01"},
  {"key 10/val 10, key 11/val 11, key 12/val 12"}, {"key 20/val 20"} }}
\begin{document}

\setcounter{grpcnt}{0}

\foreach \grp in \groups {%
    \section*{\grp}
    \pgfmathparse{\keyvals[\thegrpcnt]}
    \foreach \key/\val in \pgfmathresult
    {%
      \textbf{\key}: \val \\[1ex]
    }%
    \addtocounter{grpcnt}{1}%
}

\end{document}

enter image description here

What are the “dangerous” commands? It's not easy to tell. But font changing commands surely are, as well as some other text producing ones.


A completely different implementation that doesn't require any protection; the input of groups is changed, but I believe that a group and its corresponding list should be input together.

\documentclass{article}
\usepackage{xparse,indentfirst}

\ExplSyntaxOn
\NewDocumentCommand{\definegroup}{mm}
 {
  \shrodi_define_group:nn { #1 } { #2 }
 }
\NewDocumentCommand{\processgroups}{ }
 {
  \shrodi_process_groups:
 }

\seq_new:N \g_shrodi_groups_seq
\cs_new:Npn \__shrodi_make_name:n #1
 {
  g_shrodi_\tl_to_str:n{#1}_clist
 }
\cs_new_protected:Npn \shrodi_define_group:nn #1 #2
 {
  \seq_gput_right:Nn \g_shrodi_groups_seq { #1 }
  \clist_new:c { \__shrodi_make_name:n { #1 } }
  \clist_gset:cn { \__shrodi_make_name:n { #1 } } { #2 }
 }
\cs_new_protected:Npn \shrodi_process_groups:
 {
  \seq_map_inline:Nn \g_shrodi_groups_seq
   {
    \section* { ##1 }
    \clist_map_inline:cn { \__shrodi_make_name:n { ##1 } }
     {
      \shrodi_print_contents:nn ####1
     }
   }
 }
\cs_new_protected:Npn \shrodi_print_contents:nn #1 #2
 {
  \textbf{ #1 }: ~ #2 \par \medskip
 }
\ExplSyntaxOff

\definegroup{grp1}{
  {key 00}{val \emph{00}},
  {key 01}{val 01}
}
\definegroup{grp2}{
  {key 10}{val 10},
  {key 11}{val 11},
  {key 12}{val 12}
}
\definegroup{grp3}{
  {key 20}{val 20}
}

\begin{document}

\processgroups

\end{document}
2
  • Should I delete my answer? My Option 2 is essentially the same. I found it in pgfmanual but you posted this while I was editing my answer.
    – cfr
    Commented Feb 21, 2014 at 1:15
  • @cfr Your option 1 is not that bad, IMO.
    – egreg
    Commented Feb 21, 2014 at 8:52
2

Option 1

You could store the information indirectly. For example, along with the key and value, you could add a third element to signal a format directive. Your code would then test that and format the value of e.g. \val appropriately.

Note that the following example works by adding the text formatting command without the leading backslash e.g. emph not \emph. The command is then reconstructed using \csname ... \endcsname. Note that I have no idea if this is a good idea or not.

\documentclass{article}
\usepackage{tikz}
\newcounter{grpcnt}
\def\groups{grp1, grp2, grp3}
\def\keyvals{{ {"key 00/val 00/emph, key 01/val 01"}, {"key 10/val 10, key 11/val 11, key 12/val 12"}, {"key 20/val 20"} }}
\begin{document}
\setcounter{grpcnt}{0}
\foreach \grp in \groups {
    \section*{\grp}
    \pgfmathparse{\keyvals[\thegrpcnt]}
    \foreach \key/\val/\form in \pgfmathresult
    {
      \edef\tempa{}%
      \edef\tempb{\form}%
        \textbf{\key}: \ifx\tempa\tempb\val\else\expandafter\csname\form\endcsname{\val}\fi \\[1ex]
    }
    \addtocounter{grpcnt}{1}
}
\end{document}

Styled <code>\val</code>

Option 2

Just use the method mentioned in the documentation for pgf and protect the commands with \noepand. (See e.g. page 529 of the manual.)

\documentclass{article}
\usepackage{tikz}
\newcounter{grpcnt}
\def\groups{grp1, grp2, grp3}
\def\keyvals{{ {"key 00/val \noexpand\emph{00}, key 01/val 01"}, {"key 10/val 10, key 11/val 11, key 12/val 12"}, {"key 20/val 20"} }}
\begin{document}
\setcounter{grpcnt}{0}
\foreach \grp in \groups {
    \section*{\grp}
    \pgfmathparse{\keyvals[\thegrpcnt]}
    \foreach \key/\val in \pgfmathresult
    {
        \textbf{\key}: \val \\[1ex]
    }
    \addtocounter{grpcnt}{1}
}
\end{document}

Partially styled <code>\val</code> with <code>\noexpand</code>

1
  • Well thought! However I need to be able to format only some words and not others, like only the "00" in my example... In my real-life case, the values are whole sentences and sometimes I would need to use italics or bold on some words, so I need to be able to mark a word independently.
    – shrodi
    Commented Feb 21, 2014 at 0:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .