6

I was thinking recently that it would be really useful to have a macro that would fill in full stops between the letters of an acronym, say \acr which would take an input \acr{WHO} and spit out ‘W.H.O.’. I don’t know what the proper treatment in LaΤεΧ is for acronyms and initialisms (better to use an individual macro for each?) but whatever the case it would be useful to be able to punctuate them effortlessly. Does anyone know how to do this?

6

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 short and easy to modify for people who don't know regular expressions, so I'm accepting this answer. Could I ask you to comment it a little bit, however? – confusedandbemused Jun 26 at 7:34
  • @confusedandbemused Thanks, and done! – Steven B. Segletes Jun 26 at 10:18
  • @StevenB.Segletes Nice suggestion.... – MadyYuvi Jun 26 at 11:48
4

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

3

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

  • If I compile the code then I got the error ! Undefined control sequence. \NewExpandableDocumentCommand {\dacr}{m} is it due to version problem? – MadyYuvi Jun 26 at 11:50
  • @MadyYuvi You seem to have an outdated TeX distribution; \NewExpandableDocumentCommand has been available since 2016/2017 – egreg Jun 26 at 12:40
  • As stated elsewhere,I don't know regular expressions, so this answer isn't optimal for me. On the other hand the fact that it can take groups of letters is really neat. One thing I'm wondering about is what if you want spaces between the full stop and the next letter, except for the last one? Using the accepted answer, the code would be \newcommand\acr[1]{\acraux#1\relax\relax$\!$} \def\acraux#1#2\relax{\ifx\relax#1\else#1.\,\acraux#2\relax\fi} What about with yours? – confusedandbemused Jun 26 at 13:02
  • @confusedandbemused Am I using regular expressions? Not at all. – egreg Jun 26 at 13:50
  • @confusedandbemused I added the code for the spaces. – egreg Jun 26 at 14:07

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.