1

I have an abbreviation "f.o.o.". However, I might later want to change it to simply "foo". I thus define a macro in order to easily switch (by (un)commenting the relevant lines) between the two options:

\documentclass{article}

% f.o.o. option
\newcommand{\foo}{f.o.o.\@}
% foo option
%\newcommand{\foo}{foo}

\begin{document}
It could be a \foo{}, but then it might not be a \foo{}.
\end{document}

This works just fine, except for the trailing period. If I use the foo option, then the text is displayed correctly as:

It could be a foo, but then it might not be a foo.

However, if I use the f.o.o. option, then there's one period too many:

It could be a f.o.o., but then it might not be a f.o.o..

Is there some clever way to dynamically remove a trailing period with the f.o.o. option? This question provides a nice way to use xstring to remove a trailing period, but I don't know how to get \newcommand to look ahead to the following character.

2 Answers 2

2

Here I first check whether the next token is {; in case it is, the contents of the braces (usually empty) is delivered and reexamined.

If a period follows, it is ignored and so the standard sentence-ending space is used; otherwise \@ is issued.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\foo}{}
 {
  f.o.o.
  \peek_catcode:NTF \c_group_begin_token
   {
    \dwolfeu_foo_brace:n
   }
   {
    \dwolfeu_foo_checkperiod:
   }
 }

\cs_new_protected:Nn \dwolfeu_foo_brace:n
 {% deliver the argument unbraced
  \dwolfeu_foo_checkperiod: #1
 }

\cs_new_protected:Nn \dwolfeu_foo_checkperiod:
 {
  \peek_charcode_remove:NTF . {} { \@ }
 }

\ExplSyntaxOff

\begin{document}

\xspaceskip=20pt

It could be a \foo{}, but then it might not be a \foo{}. Text follows.

It could be a \foo, but then it might not be a \foo. Text follows.

It could be a \foo{} with normal space.

It could be a \foo. With sentence-ending space.

\end{document}

I used a big value of \xspaceskip just to better show when the sentence-ending space is used.

enter image description here

10

If you want to use only TeX primitives then you can use this code:

\def\foo{f.o.o.\checknextdot}
\def\checknextdot{\futurelet\next\checknextdotA}
\def\checknextdotA{\let\nextA=\relax
   \ifx\next.\def\nextA##1{}\fi
   \ifx\next\bgroup\def\nextA##1{\checknextdot}\fi
   \nextA
}

In OpTeX, you can use following macros:

\def\foo{f.o.o.\checknextdot}
\def\checknextdot{\isnextchar.{\ignoreit}%
                              {\isnextchar\bgroup{\ea\checknextdot\ignoreit}
                                                 {}}}

Testing code for both variants:

It could be a \foo{}, but then it might not be a \foo{}. Text follows.

It could be a \foo, but then it might not be a \foo. Text follows.

It could be a \foo{} with normal space.

It could be a \foo. With sentence-ending space.
3
  • 1
    Alas neither solution works for me: The TeX-primitives-only solution causes my console to hang, while I'm not using OpTeX and so \isnextchar throws an error.
    – dwolfeu
    Commented Sep 28, 2022 at 20:31
  • 2
    @dwolfeu I created a file test.tex with 7 lines of "primitive" macros followed by 7 lines of testing code followed by \bye. Then I run pdftex test. Nothing hangs, pdf file is created. Second: I created testl.tex file with \documentclass{article} followed by 7 lines of the "primitive" macros followed by \begin{document} followed by 7 lines of testing code followed by \end{document}. Then I run pdflatex testl.tex. Nothing hangs, pdf file is created. What did you do?
    – wipet
    Commented Sep 29, 2022 at 16:14
  • 1
    I apologise: The issue was not with your solution but with the command \titlecap{\foo{}} (from the package titlecaps). Incidentally, the down-vote for your answer was not from me.
    – dwolfeu
    Commented Sep 30, 2022 at 8:34

You must log in to answer this question.

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