3

I'm trying to define a simple way to handle keywords in my university thesis template. They are used in different parts of the thesis, with different notations, so I decided to keep them in different macros. I did a similar in the past thing to keep the examiners' names.

It works fine when defining them one by one, like:

\myKeyword{key 1}
\myKeyword{key 2}

I tried then to create a macro where I could declare all of them together, but keep them still separated (for further use). However, for some reason, it does not work as I expected.

Here is an MWE:

\documentclass{standalone}

\usepackage{tikz} %foreach
\usepackage{forloop} %forloop

% counters declaration
\newcounter{myKeywordCounter}
\newcounter{currentKeywordCounter}

\newcommand{\myKeyword}[1]{%
  \expandafter\newcommand\csname myKeyword\arabic{myKeywordCounter}\endcsname{#1}\relax%
  \stepcounter{myKeywordCounter}%
}%

\newcommand{\declareKeywords}[1]{%
    \foreach \argtext in {#1} {%
        \myKeyword{\argtext}%
    }%
}%

\newcommand{\printKeywords}{\textbf{Keywords}: %
    \forloop{currentKeywordCounter}{0}{\value{currentKeywordCounter} < \value{myKeywordCounter}}%
    {%
        \expandafter\csname myKeyword\arabic{currentKeywordCounter}\endcsname{}. %
    }%
}%

\begin{document}
    \declareKeywords{{key A},{key B},{key C}}
    \myKeyword{key 1}
    \myKeyword{key 2}
    \myKeyword{key 3}
    \printKeywords{}
\end{document}

Which prints only keys A, B, and C, whereas does not print 1, 2, and 3:

enter image description here

It seems that when nested, the new 'myKeywordX' (X is an arabic number) is not able to expand to #1. I'm not sure about that... Any thoughts?

2
  • 1
    Untested, but I think this is the grouping caused by \foreach...
    – user31729
    Dec 12, 2017 at 17:43
  • You should look into the expl3 language enhancements, it might be easier to achieve with those what you request
    – user31729
    Dec 12, 2017 at 17:54

2 Answers 2

3

The grouping caused by \foreach will never give \mykeyword0 etc. being defined, so it will not change.

The easiest way is to use either a \global\@namedef or a \gdef macro together with the expanded value of `\argtext

\documentclass{article}

\usepackage{tikz} %foreach
\usepackage{forloop} %forloop

% counters declaration
\newcounter{myKeywordCounter}
\newcounter{currentKeywordCounter}

\newcommand{\myKeyword}[1]{%
  \expandafter\gdef\csname myKeyword\arabic{myKeywordCounter}\endcsname{#1}\relax%
  \stepcounter{myKeywordCounter}%
}%

\newcommand{\declareKeywords}[1]{%
    \foreach \argtext in {#1} {%
      \expandafter\myKeyword\expandafter{\argtext}%
    }%
}%

\newcommand{\printKeywords}{\textbf{Keywords}: %
    \forloop{currentKeywordCounter}{0}{\value{currentKeywordCounter} < \value{myKeywordCounter}}%
    {%
        \expandafter\csname myKeyword\arabic{currentKeywordCounter}\endcsname{}. %
    }%
}%

\begin{document}
    \declareKeywords{{key A},{key B},{key C}}
  %  \myKeyword{key 1}
  %  \myKeyword{key 2}
  %  \myKeyword{key 3}
    \printKeywords{}
\end{document}
4
  • Tks, it works! I understand the gdef, but i didnt understand well the \expandafters in the foreach part. Could you elaborate on that? Is this because gdef canot use an 'unexpanded' macro?
    – Isma
    Dec 12, 2017 at 17:55
  • 1
    @Isma: On the usage of \printKeywords \csname mykeyword0\endcsname would try to expand \argtext which isn't defined any longer in \printKeywords -- you have to force the replacement text (i.e. the expansion of the relevant \argtext from the loop into the \mykeyword{\argtext}, i.e. \expandafter\mykeyword\expandafter{\argtext} One \expandafter is not enough there, i.e. \expandafter\mykeyword{\argtext} would try to expand the {, which is not expandable, you have to 'jump' over the \mykeyword, expand the argument \argtext and then let \mykeyword do the job
    – user31729
    Dec 12, 2017 at 18:00
  • I see it now! Tks again !
    – Isma
    Dec 12, 2017 at 18:02
  • @Isma: You're welcome. Happy TeXing
    – user31729
    Dec 12, 2017 at 18:03
2

The grouping in \foreach is the cause of your troubles.

Here's a different implementation based on expl3, where each \myKeyword or \declareKeywords command add the item to a sequence that can be later processed.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\myKeyword}{m}
 {
  \isma_keywords_add:n { #1 }
 }

\NewDocumentCommand{\declareKeywords}{m}
 {
  \clist_map_inline:nn { #1 }
   {
    \isma_keywords_add:n { ##1 }
   }
 }

\NewDocumentCommand{\printKeywords}{}
 {
  Keywords:~
  \seq_map_inline:Nn \g_isma_keywords_seq
   {
    ##1.~
   }
 }

\NewDocumentCommand{\getKeyword}{m}
 {
  \seq_item:Nn \g_isma_keywords_seq { #1 }
 }

\seq_new:N \g_isma_keywords_seq

\cs_new_protected:Nn \isma_keywords_add:n
 {
  \seq_gput_right:Nn \g_isma_keywords_seq { #1 }
 }

\ExplSyntaxOff

\begin{document}

\declareKeywords{key A,key B,key C}

\myKeyword{key 1}
\myKeyword{key 2}
\myKeyword{key 3}

\printKeywords

\getKeyword{2}

\getKeyword{4}

\end{document}

enter image description here

You must log in to answer this question.

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