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?

  • 1
    Untested, but I think this is the grouping caused by \foreach... – user31729 Dec 12 '17 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 '17 at 17:54
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}
  • 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 '17 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 '17 at 18:00
  • I see it now! Tks again ! – Isma Dec 12 '17 at 18:02
  • @Isma: You're welcome. Happy TeXing – user31729 Dec 12 '17 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

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.