# [texhax] Add a dot at the end of a sentence if not placed already

Ian.Collier at comlab.ox.ac.uk Ian.Collier at comlab.ox.ac.uk
Tue Jul 5 13:59:49 CEST 2005

torsten.wagner at fh-aachen.de (Torsten Wagner) expounded:
>O.K. My lovely boss asked me to give all captions a dot at the end of
>the sentence. The problem, I have 100 of different files from 100 of
>different authors. Some placed a dot, some not.

OK, this is a hack and might not be the best way to do it, but it seems to
work...

{\catcode\X=3 \catcode\Y=3
\gdef\ensuredot#1{#1\if.\detectdot#1X.Y\else.\fi}
\gdef\detectdot#1.#2Y{\ifY#2Y!\else\ifX#2\else\detectdot#2Y\fi\fi}
}

Now \ensuredot{foo} expands to {foo.} while \ensuredot{bar.} expands
to {bar.}.  You can probably now define something like

\let\originalcaption=\caption
\def\caption#1{\originalcaption{\protect\ensuredot{#1}}}

to change the definition of \caption, though this will break any caption
that has a square-bracketed optional argument and you'll have to work
harder to insert the \ensuredot into the definition of \caption if you
want it to work for all cases.

Danger: if the argument to \ensuredot has a space at the end then it
effectively doesn't end with a dot, and the macro will add one.  This
will look ugly.

Explanation of the code:
X and Y are sentinels; they need to be characters that are guaranteed
not to appear elsewhere in the document.  Changing their catcodes to
some random value ensures this, though there may be other ways to
achieve the same effect.

The \detectdot macro is designed to be invoked with some text followed
by X.Y and will expand to "." (a single dot) if the text ends with a
dot, or "!" if it doesn't.  So the \ensuredot macro uses this to test
whether the dot is present and adds it if not.

When you call \detectdot, TeX puts any text up to the first dot into #1,
gobbles the dot, and puts the rest of the parameters up to Y in #2.  (The
caller has ensured that both the dot and the Y are present by adding X.Y
to the end of the text.)  The macro effectively ignores #1 and examines #2.

If the text didn't contain a dot then TeX will split it at the dot from the
string X.Y and so #2 will be empty.  The test "\ifY#2Y!" tests whether #2 is
empty and returns a single "!" if that is the case.

If the text had a dot at the end (and no other dot) then TeX will split
it at that dot, and #2 will contain the "X." from the string X.Y.  The
test "\ifX#2" tests this and returns the dot if that is the case.

Otherwise, the text must have had a dot in the middle, so the macro calls
itself again after throwing away the text leading up to the dot.

--
---- Ian Collier : imc at comlab.ox.ac.uk : WWW page below
------ http://users.comlab.ox.ac.uk/ian.collier/imc.shtml