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}

enter image description here


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:

enter image description here


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}

enter image description here

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}

enter image description here

Tags:

Macros

Luatex