Inserting full stops between letters with a macro
What I do here is set up an recursion. The called \acr
macro passes the argument to the helper macro \acraux
terminated by two \relax
tokens. The helper macro breaks the argument into the "next" token and everything else that remains (terminated by a \relax
).
It will typeset the "next" token with a trailing dot, as long as that next token is not a \relax
. Then it will recursively call upon itself, repeating this task while eating up the remainder of the argument. The 2nd \relax
comes into play when the iteration is nearing its end (i.e., when there are no lettered tokens left). At that point, what would normally be the terminating \relax
gets absorbed by \acraux
as #1
and so another \relax
is sought to terminate the argument of \acraux
. It finds the 2nd \relax
that was originally supplied with the invocation. And now that #1
is \relax
, it terminates the recursion.
I could revise it a bit to prevent the recursion from being stack-bound, but as I don't expect the acronym to exceed 64K letters, the problem is moot. (Note: the recursion is stack-bound because \acraux
is successively called before the terminating \fi
is expanded.)
\documentclass{article}
\newcommand\acr[1]{\acraux#1\relax\relax}
\def\acraux#1#2\relax{\ifx\relax#1\else#1.\acraux#2\relax\fi}
\begin{document}
\acr{WHO}
\end{document}
As some of the other answers have addressed, one may desire the spacing between letters of the acronym to vary from the default. Here is one way:
\documentclass{article}
\def\acrspace{1.5pt}
\newcommand\acr[1]{\kern-\acrspace\acraux#1\relax\relax}
\def\acraux#1#2\relax{\ifx\relax#1\else\kern\acrspace#1.\acraux#2\relax\fi}
\begin{document}
Spacing about \acr{WHO} returned to normal.
\end{document}
This is easy to do using LaTeX3 regular expressions. In more detail, the code:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand\acr{m}{
\tl_set:Nn \l_tmpa_tl {#1}
\regex_replace_all:nnN {([A-Z])} {\1.} \l_tmpa_tl
\tl_use:N \l_tmpa_tl
}
\ExplSyntaxOff
\begin{document}
\acr{WHO}
\end{document}
produces:
Map the input item by item, adding \@.
(this is because the last period might follow a lowercase character).
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\dacr}{m}
{
\confusedandbemused_dacr:n { #1 }
}
\cs_new:Nn \confusedandbemused_dacr:n
{
\tl_map_function:nN { #1 } \__confusedandbemused_dacr_add:n
}
\cs_new:Nn \__confusedandbemused_dacr_add:n
{
#1\@.
}
\ExplSyntaxOff
\begin{document}
\dacr{WHO}
\dacr{DA{Spo}}
\end{document}
The modification for adding spaces after the period, except the last one, is relatively straightforward: I isolate the first item (with \tl_head:n
) and process the rest of the items placing .\nobreakspace
before them. After the last item I put \@.
.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\dacr}{m}
{
\confusedandbemused_dacr:n { #1 }
}
\cs_new:Nn \confusedandbemused_dacr:n
{
\tl_head:n { #1 }
\tl_map_function:eN { \tl_tail:n { #1 } } \__confusedandbemused_dacr_add:n
\@.
}
\cs_generate_variant:Nn \tl_map_function:nN { e }
\cs_new:Nn \__confusedandbemused_dacr_add:n
{
.\nobreakspace#1
}
\ExplSyntaxOff
\begin{document}
$|$\dacr{WHO}$|$
$|$\dacr{DA{Spo}}$|$
\end{document}