# How can I check if a header has an ending full stop?

I am modifiyng some macros to enforce a section style that should end with a full stop. The full stop is added automatically, but sometimes people add the full stop and I get two. How can I modify the code to detect the punctuation and add it only if it is needed? I guess I need to use futurelet, but I don't know how to use it.

-
It would be helpful to compose a fully compilable MWE that illustrates the problem including the \documentclass and the appropriate packages so that those trying to help don't have to recreate it. This will also clarify any ambiguities in your question. –  Peter Grill Mar 2 '12 at 5:07
@PeterGrill I am sorry the code was really long. Will give one in my next question. –  Chuang Mar 2 '12 at 5:24
Ok. But keep in mind, everyone's real code is really long. The point is to create a new document as small as possible that reproduces the problem. In this case you could just define a macro that adds punctuation and passes it two test cases: one with the punctuation, one without? –  Peter Grill Mar 2 '12 at 16:38

Firstly it is always best to post a MWE. As you have not posted one I am posting a general answer, for exact formatting of the section you will need to add your own formatting commands.

You don't need a \futurelet. TeX keeps track of special codes for letters and punctuation to place the right amount of space after a stop. We can check the value of the \spacefactor macro and add a stop or do nothing if it is already there.

\newcommand\@addpunctuation[1]{\ifnum\spacefactor>1000\else#1\fi}


The rest of the code are minor details. Here is the MWE.

\documentclass{article}
\makeatletter
\def\section{\secdef \starcmd \unstarcmd}
\makeatother
\parindent0pt
\begin{document}
\makeatletter

\section[small title]{Testing}\\
\section{Testing}\\ % remains as is
\Section{Testing}\\
\Section{Testing.}
\end{document}


If you want the macro to work both for \frenchspacing and \nonfrenchspacing, you can try:

\newcommand\@addpunctuation[1]{%
\nonfrenchspacing
\ifnum\sfcode.=1000
\ifnum\spacefactor>1000\else#1\fi
\else
\ifnum\spacefactor>1000\else#1\fi
\nonfrenchspacing
\fi
}


and test with

\frenchspacing

Test. \fbox{A test test}

\nonfrenchspacing

Test. \fbox{A test test}


You can also visit the link quoted by Philippe Goutet in the comments below.

-
The last example entry has two dots if \frenchspacing is active. –  morbusg Mar 2 '12 at 6:14
@morbusg \frenchspacing sets all the sfcodes to 1000 so one would have to modify the above to check for frenchspacing. Perhaps a better technique is to check the value of the sfcode for the stop and then do the check. –  Yiannis Lazarides Mar 2 '12 at 6:23
@morbusg: see \frenchspacing not setting the space factor codes correctly? for how the ams solved the problem with its \@addpunct macro. –  Philippe Goutet Mar 2 '12 at 10:56
@PhilippeGoutet Thanks for the link. I posted an alternative in the answer which I had already worked out, would you please care to check it out and comment on it? –  Yiannis Lazarides Mar 2 '12 at 11:09
@YiannisLazarides: Using your \@addpunctuation macro with \frenchspacing, I get two dots. The problem with the idea of starting \@addpunctuation with \nonfrenchspacing is that the space factor has already been set, so it's too late as \frenchspacing Text.\nonfrenchspacing\the\spacefactor will show. I don't think you can get around redefining \frenchspacing as the AMS did. –  Philippe Goutet Mar 2 '12 at 13:26

The problem can be solved at a macro level without 'meddling' with the space factor.

\documentclass{article}
\makeatletter
\usepackage{catoptions}
\robust@def*\newsection#1{%
\begingroup
\edef\currtitle{\cpttrimspaces{#1}}%
\def\currlabel{}\def\lasttok{}%
\xifinsetFT{\detokenize{\label}}{\cptoxdetok\currtitle}{}{%
\def\reserved@a##1\label##2##3\cpt@nil{%
\def\currtitle{##1##3}%
\def\currlabel{\noexpand\label{##2}}%
}%
\expandafter\reserved@a\currtitle\cpt@nil
}%
\def\getlasttok##1{%
\expandafter\ifx\@car##1\@nil\cpt@nnil
\else
\edef\lasttok{\unexpanded{##1}}%
\expandafter\getlasttok
\fi
}%
\expandafter\getlasttok\currtitle\cpt@nnil
\s@expandarg\ifinsetTF\lasttok{\dots\ldots\textellipsis}{%
\@tempswatrue
}{%
\begingroup
\lccode\X=133
\lowercase{\endgroup\expandafter\expandafter\expandafter
\ifstrcmpTF\expandafter\@car\lasttok\@nil X}{%
\@tempswatrue
}{%
\@tempswafalse\let\elt\relax
\def\siso@do##1{%
\xifinsetFT{\detokenize{##1}\elt}{\cptoxdetok\currtitle\elt}{}{%
\@tempswatrue\loopbreak
}%
}%
\siso@@loop{.!?:\dots\ldots\textellipsis}%
}%
}%
\def\elt{\expandcsonce\currtitle}%
\cptexpandarg{\endgroup\section}{\if@tempswa\elt\else\elt.\fi\currlabel}%
}
\makeatother

\begin{document}
\newsection{Test section.\label{sec:1}}
As seen later in Section~\ref{sec:this} \ldots.
\newsection{Test section}
\newsection{Test section.}
\newsection{Is this a test section?}
\newsection{Heh, this is test section!}
\newsection{Test section\dots}
\newsection{Test section\ldots}
\newsection{Test section\textellipsis}
\newsection{Test section\label{sec:this}\ldots}
As seen earlier in Section~\ref{sec:1} \ldots.

% I have accounted for the ASCII character 133 but you may not get it to print:
\newsection{Test section …}
\end{document}

-
This will not work with \dots: \newsection{Test section\dots} will give four dots instead of three –  Philippe Goutet Mar 3 '12 at 7:48
@PhilippeGoutet: Please do you have other failure modes, so that I can try to address them at once? –  Ahmed Musa Mar 3 '12 at 14:50
Well, it should work with all the punctuation so it is safer to also add , and : and ; but that should be all. Of course, the solution should also work with \ldots, \textellipsis  or other \dots variants as well as the symbol … (in unicode, U+2026). –  Philippe Goutet Mar 3 '12 at 16:05
@PhilippeGoutet: I haven't seen section and paragraph headings ending with comma (,) or semicolon (;). So I think we should leave them out. –  Ahmed Musa Mar 3 '12 at 17:03
Well, for inline sections, you could imagine things like \paragraph{Start of the title,} end of the title. (I've done this myself a few times). Anyway, as a comma or a semi-colon should never be followed by a full stop, just as well add them, it's safer. You never know what can cross the mind of your end users. –  Philippe Goutet Mar 3 '12 at 18:54