8

I want to use the command \DTLstoreinitials from package \usepackage{datatool} in the following way :

\newcommand{\extractInitials}[1]{%
\DTLstoreinitials{#1}{\userInitials}%
\DTLsubstituteall{\userInitials}{.}{}%remove points between the initials
\DTLsubstituteall{\userInitials}{ }{}%remove spaces
\userInitials%
}

If I call the command directly, it works :

\extractInitials{My Name}

gives MN. But if I use an auxiliary command: \newcommand{\nom}{My Name} and try to call

\extractInitials{\nom}

then the compilation fails with error

! Paragraph ended before \@dtl@initials was complete.

How can I fix this?


Here is a minimal example 1 :

\documentclass[12pt]{article}
\usepackage{trackchanges}
\usepackage{datatool}

\newcommand{\extractInitials}[1]{%
%\expandafter\DTLstoreinitials\expandafter{#1}{\userInitials}%
\DTLstoreinitials{#1}{\userInitials}%
\DTLsubstituteall{\userInitials}{.}{}%remove points 
\DTLsubstituteall{\userInitials}{ }{}%remove spaces
}
\begin{document}
\extractInitials{AAA BBB}\addeditor{\userInitials}
\extractInitials{CCC DDD}\addeditor{\userInitials}
----------- \\% to see the result of the addeditor commands
\makeatletter
\TC@editorOne\\
\TC@editorTwo\\
\TC@editorThree\\
\makeatother
-----------
\end{document}

The output is CD n/n n/n To compare : example 2

\addeditor{AB}
\addeditor{CD}
----------- \\% to see the result of the addeditor commands
\makeatletter
\TC@editorOne\\
\TC@editorTwo\\
\TC@editorThree\\
\makeatother
-----------

The output is AB CD n/n

3
  • You don't have to sign with your name since it automatically appears in the lower right corner of your post. I've edited your post accordingly.
    – Werner
    Dec 21, 2011 at 23:13
  • Welcome to TeX.sx! Note that you can edit your posts to add more information. Answer posts are for solutions to the question. Dec 22, 2011 at 22:09
  • I've added note 3.
    – egreg
    Dec 22, 2011 at 22:34

1 Answer 1

5

You have two choices.

First

\newcommand{\extractInitials}[1]{%
  \expandafter\DTLstoreinitials\expandafter{#1}{\userInitials}%
\DTLsubstituteall{\userInitials}{.}{}%remove points between the initials
\DTLsubstituteall{\userInitials}{ }{}%remove spaces
\userInitials
}

This can be used if \nom expands immediately to the name and no more processing is needed.

The trick is to access at #1 before processing by \DTLstoreinitials begins. The first \expandafter acts on the second, which in turn expands the first token after the brace: in your case it can be \nom; if you give directly a name nothing happens (but see the second note).

Second

\makeatletter
\newcommand{\extractInitials}[1]{%
  \begingroup\protected@edef\x{%
    \endgroup\noexpand\DTLstoreinitials{#1}{\noexpand\userInitials}}\x%
\DTLsubstituteall{\userInitials}{.}{}%remove points between the initials
\DTLsubstituteall{\userInitials}{ }{}%remove spaces
\userInitials
}
\makeatother

This is to be preferred if the contents of \nom is more complicated (say \nom becomes \Prenom\space\Nom. Here we expand until the bottom, but "robusted" macros such as those for accented letters remain untouched.

Note 1

Using \edef in this context directly is bound to break if the argument of \extractInitials contains accented characters (even when a control sequence is used).

Note 2

In both cases, results are unpredictable if the first initial is an accented letter. Put it as {É}lie Cartan to get a correct result. However, none of the method works reliably in this case if the input encoding is UTF-8 (for limitations of datatool). Write always a first accented initial in braces.

Note 3

In case this macro must be fed to another command, the result will depend on what this macro does. For example it will work with \textbf{\extractInitials{My Name}}, since \textbf wants only to print its argument. In other cases a different approach must be taken; for example, in your test document one has to take an indirect path:

\newcommand{\extractInitials}[1]{%
  \expandafter\DTLstoreinitials\expandafter{#1}{\userInitials}%
\DTLsubstituteall{\userInitials}{.}{}%remove points between the initials
\DTLsubstituteall{\userInitials}{ }{}%remove spaces
}
\newcommand{\myaddeditor}[1]{%
  \extractInitials{#1}\expandafter\addeditor\expandafter{\userInitials}}

and then say \myaddeditor{AAA BBB}

7
  • Thank you very much. I will use the first one, since \nom expands immediately to the name in my case, and i have accented letter. It works, but i don't quite understand the trick :). Could you explain it to me ? I understand the first \expandafter, it insure that the argumen #1 will be first expanded. But why to "expand" \userItinials ? I thought this is a temporary command where DTLstoreinitials stores the result of the string operation... Dec 22, 2011 at 9:38
  • Another problem i'm facing : i'm using the result of \extractInitials in some other command \somecommand{\extractInitials{My Name}} but it fails. This command is one from a package, and i don't know exactly how it is defined. But is there a way to make \extractInitials completely expand, before we give it as an argument to \somecommand, so that the compilation doesnt fails, even if we don't know how \somecommand is build ? Dec 22, 2011 at 10:22
  • @nicolasroy Please add to the question a minimal example; you should register on the site (the moderators can then merge other questions you submitted as an unregistered user).
    – egreg
    Dec 22, 2011 at 11:45
  • Well, my question was precisely, how can i make the command \extractInitials sufficiently robust, so that i can use it inside any command in the future... But ok, for the moment, i want to be able to use: \addeditor{\extractInitials{My Name}} where \addeditor is a command from the package trackchanges. Dec 22, 2011 at 18:11
  • @nicolasroy If you cut the last \userInitials from the main macro and say \extractInitials{My Name}\addeditor{\userInitials} it might work (maybe with a couple of \expandafters).
    – egreg
    Dec 22, 2011 at 18:14

You must log in to answer this question.

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