# Insert a period / full stop if caption argument doesn't end with one

I have a command \Notes which simply is a caption under a figure:

\newcommand{\Notes}[1]{\captionsetup{position=below}\caption*{#1}}


I would like the punctuation to be consistent in the caption, always closing with a full stop. That is, I'd like the following MWE to have Notes. in the first figure, as well as Notes with full stop. (as is) in the second figure. Can LaTeX enforce this policy?

\documentclass{scrartcl}
\usepackage{caption}
\usepackage{graphicx}

\newcommand{\Notes}[1]{\captionsetup{position=below}\caption*{#1}}

\begin{document}

\begin{figure}
\caption{Actual caption}
\includegraphics{Example-image}
\Notes{Notes}
\end{figure}

\begin{figure}
\caption{Another caption}
\includegraphics{Example-image}
\Notes{Notes with full stop.}
\end{figure}

\end{document}

• This is a really good question – Au101 Oct 19 '16 at 2:17

It's as easy as loading amsthm, which defines an \@addpunct command, which will insert its argument only if no punctuation precedes it.

\documentclass{scrartcl}
\usepackage{amsthm}% yes, that's it!
\usepackage{caption}
\usepackage{graphicx}

\makeatletter
\makeatother

\begin{document}

\begin{figure}[htp]
\centering
\caption{Actual caption}
\includegraphics[width=4cm]{example-image}
\Notes{Notes}
\end{figure}

\begin{figure}[htp]
\centering
\caption{Another caption}
\includegraphics[width=4cm]{example-image}
\Notes{Notes with full stop.}
\end{figure}

\begin{figure}[htp]
\centering
\caption{Another caption}
\includegraphics[width=4cm]{example-image}
\Notes{Notes with exclamation mark!}
\end{figure}

\end{document}


The following example evaluates the space factor at the end of the caption to detect, if there was a punctuation char before.

\documentclass[a5paper]{scrartcl}
\usepackage[paperheight=7cm]{geometry}% for smaller image in answer for TeX.SX
\usepackage{caption}
\usepackage{graphicx}

\newcommand{\Notes}[1]{\captionsetup{position=below}\caption*{#1}}

\makeatletter
\newcommand*{\RedefCaption}{%
\let\org@caption\@caption
\let\@caption\dot@caption
}
\def\dot@caption#1[#2]#3{%
\dot@test@def\tmp@a{#2}%
\dot@test@def\tmp@b{#3}%
\org@caption{#1}[\tmp@a]\tmp@b
}
\newcommand*{\dot@test@def}[2]{%
\begingroup
% Set space factor to values larger than 1000 for punctuation characters
\nonfrenchspacing
% Set space factor to 1000 for upper case letter, which usually
% have 999. This supports abbreviations: After an uppercase letter
% the space factor is 999, a period would want it to set to 3000,
% but TeX does not increase over 1000 in one step. Thus, the
% space factor is 1000 after "A.".
% Here, we do not want to support abbreviations, because
% a period needs to be omitted, if there was a dot before,
% regardless if the previous dot marks the end of the sentence
% or belongs to an abbreviation.
\count@=\@\relax
\@whilenum\count@<\Z\do{%
\advance\count@\@ne % \@ne = 1
\sfcode\count@=\@m % \@m = 1000
}%
\sbox0{#2%
\ifnum\spacefactor>\@m
\global\let\dot@found=Y%
\else
\global\let\dot@found=N%
\fi
}%
\endgroup
\if\dot@found Y%
\def#1{#2}%
\else
\def#1{#2.}%
\fi
}
\AtBeginDocument{\RedefCaption}
\makeatother

\begin{document}

\begin{figure}
\caption{Actual caption}
% \includegraphics{Example-image}
\Notes{Notes}
\end{figure}

\begin{figure}
\caption{Another caption}
% \includegraphics{Example-image}
\Notes{Notes with full stop.}
\end{figure}

\end{document}


(Your requirement wasn't entirely clear to me. I assume that you want periods (full stops) at the ends of the arguments of both \caption and \Notes. If it's only needed for \Notes, I trust you'll be able to figure out how to modify the code shown below.)

Here's a LuaLaTeX-based solution. It adds missing periods ("full stops") at the end of the arguments of \caption and \Notes instructions. It works by scanning the input, at a very early stage of processing, for instances of \caption{...} and \Notes{...} and examining the arguments; if they lack a period at the end, a period is inserted.

The only requirement for the input stream is that the commands \caption and \Notes and their respective arguments all be on the same line. I trust that this doesn't constitute a binding restriction.

%% Compile with LuaLaTeX
\documentclass{scrartcl}
\usepackage{caption}

\usepackage{luacode}
\begin{luacode*}
function add_period ( s )
if string.find ( s , "\\caption%s-{" ) then
s = string.gsub ( s , "(\\caption)%s-(%b{})",
function ( capt , argu )
argu = string.sub ( argu , 2 , -2 )
if not string.find ( argu , "%.%s-$" ) then argu = argu .. "." end return ( capt .. "{" .. argu .. "}" ) end ) end if string.find ( s , "\\Notes%s-{" ) then s = string.gsub ( s , "(\\Notes)%s-(%b{})", function ( capt , argu ) argu = string.sub ( argu , 2 , -2 ) if not string.find ( argu , "%.%s-$" ) then
argu = argu .. "."
end
return ( capt .. "{" .. argu .. "}" )
end )
end
return ( s )
end
\end{luacode*}

\newcommand{\Notes}[1]{\captionsetup{position=below}\caption*{#1}}

\begin{document}

\begin{figure}[ht!]
\caption {Actual caption}
\Notes{Notes}
\end{figure}

\begin{figure}[h!]
\caption {Another caption. } \Notes {Notes with full stop. }
\end{figure}

\end{document}


Use \@addpunct (egreg's) is clearly better/simpler than this (+1). But for the for the sake of completeness, with the xstring package you can check the end of some string with \IfEndWith.

For simplicity, assuming that you only check for full stops, not other punctuation signs, and assuming no punctuation signs in sort captions, the macro could be:

\documentclass[12pt]{article}
\usepackage{xstring,xifthen}
\newcommand\Note[2][]{
\ifthenelse{\isempty{#1}}{%
\IfEndWith{#2}{.}{\caption[#2]{#2}}{\caption[#2.]{#2.}}}{%
\IfEndWith{#2}{.}{\caption[#1.]{#2}}{\caption[#1.]{#2.}}}}
\begin{document}
\begin{figure}
\Note{Caption with period.}
\Note{Caption without period}
\Note[No]{No, without period}
\Note[Yes]{Yes, with period.}
\end{figure}
\listoffigures
\end{document}