2

I was reading the documentation on the cleveref package, which can be found here, when I stumbled upon a side remark on page six (can be found in the paragraph for \Cref), which says

As it is very difficult³ for LATEX to determine whether a cross-reference appears at the beginning of a sentence or not, [...]

³ Actually, very likely impossible!

(Changed the original Latex sign generated by \LaTeX to LATEX)

I'd like to know why this is the case?

  • 3
    Just try to automatically detect the beginning of a sentence in any programming language keeping in mind that there are abbreviations ending with a period, dots at other positions in the sentence and multiple languages and you will see that text processing can be quite difficult for these nuances. – TeXnician Dec 2 '18 at 20:13
  • 3
    Additionally, standard (La)TeX has no way to check what the last processed token was. So when the \Cref is executed, there's no simple way to check whether the character before it was a period or other punctuation mark. You could make punctuation marks macros itself that check if the following token is \Cref, but this is likely to cause trouble in other places and wouldn't be very reliable. – siracusa Dec 2 '18 at 20:16
  • 1
    What one needs is a of pre-processor approach, in which one examines the input stream as follows. (For simplicity, assume that each paragraph, or at least each sentence, is contained in a single line of input.) Then, every time the string \cref is encountered in the input stream, check if it occurs at the very start of a line or is preceded by a sentence-ending punctuation mark followed by whitespace. If one of these conditions is true, determine that \cref occurs at the start of a sentence. But this would impose a horrible amount of computing overhead, grossly slowing compilation. – Mico Dec 2 '18 at 20:35
  • @Mico I can understand the idea and the consequences of the approach you suggested, but if I understand you correctly, it could be done, it's just that the consequences of such an approach outweigh the possible advantages, right? – Sito Dec 2 '18 at 21:08
  • A \Cref when I wrote \cref? no, thanks ! For me is not a problem of computing overhead, but that I hate that the computer choose by me what to do after a period, like in " E. coli ", supposedly to gain time while typing, but in practice this kind of "AI" is useful only to waste your time while correcting the wrong uppercases and, if you are not careful, left them in the final document! Even if that AI could detect the end of a paragraph, or the end of a sentence (how?) I doubt that it could be a real benefit for the writer. – Fran Dec 2 '18 at 21:38
4

Here's a LuaLaTeX-based implementation of the preprocessor-based approach I outlined in the comments above. It replaces instances of \cref with \Cref (and of \crefrange with \Crefrange) if they occur either at the very start of a line of input or are preceded by a sentence-ending punctuation mark (., ?, or !) followed by one of more whitespaces. The main work is performed by the cref2Cref Lua function, which gets assigned to the process_input_buffer callback, thus acting as a preprocessor before TeX starts its normal work.

The main, crucial assumption about the input is that there are no line-breaks inside sentences. If this assumption isn't satisfied, the approach is not guaranteed to work. A second, hopefully trivially-true, assumption is that only macros of the cleveref package start with the string \cref. If, for whatever reason, your code defines macros named \crefx or \crefzzz, be prepared for some unpleasant surprises. The approach also ignores the possibility that non-sentence-ending periods are followed immediately by \cref. Thus, a (highly questionable!) sentence fragment such as "Mr. and Mrs. \cref{fig:a} are pleased to announce" will trip up the algorithm. Do let me know if your document contains such passages...

The code used to generate the following screenshot loads the hyperref package and loads the cleveref package with the option nameinlink in order to make it easy for the eye to detect cross-references. Observe that two of the four instances of \cref were replaced with \Cref "on the fly".

enter image description here

Finally, note that cleveref itself does no extra work here: It only ever gets to see, and process, instances of \cref and \Cref. cleveref has no way of knowing which instances of \Cref and \Crefrange were provided by the author and which ones were created on-the-fly by the Lua function cref2Cref.

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{amsmath} % for 'gather' env.
\usepackage[colorlinks]{hyperref} % optional
\usepackage[nameinlink,noabbrev]{cleveref}
\usepackage{luacode}
\begin{luacode}
function cref2Cref ( s )
   s = s:gsub ( "^\\cref", "\\Cref" )
   s = s:gsub ( "([%.%!%?])%s*\\cref" , "%1 \\Cref" )
   return s
end
\end{luacode}
%% Assign the Lua function to the 'process_input_buffer' callback:
\AtBeginDocument{\directlua{luatexbase.add_to_callback( 
  "process_input_buffer" , cref2Cref , "cref2Cref" )}}

\begin{document}
%% Set up a few equations and figures.
\begin{gather} 
1+1=2 \label{eq:1} \\
2+2=4 \label{eq:2} \\
3+3=6 \label{eq:3} 
\end{gather}
\begin{figure}[h!] 
\caption{AAA} \label{fig:a} \smallskip
\caption{BBB} \label{fig:b} \smallskip 
\caption{CCC} \label{fig:c} 
\end{figure}

% Now generate a few cross-references.
Is this a cross-reference to \cref{eq:1}? \cref{eq:2,eq:3} show that\dots

\crefrange{fig:a}{fig:c} illustrate\dots\ As \crefrange{fig:b}{fig:c} demonstrate, \dots
\end{document}
  • 1
    Thank you very much for the answer! To respond to How difficult, really, is it to develop a habit of writing \Cref at the start of a sentence?: There is absolutely no problem in writing \Cref instead of \cref where necessary, it's just that I thought the problem was interesting and I was curious about the statement, that there probably doesn't exist a solution for the problem. Once again, thanks for the answer! – Sito Dec 2 '18 at 22:45
  • 1
    @Sito - You're most welcome. Do note that the maintained assumption about the input format can be quite strong. For sure, if someone's in the habit of inserting line breaks immediately before \cref and \crefrange, the method outlined above is simply not going to work correctly. – Mico Dec 2 '18 at 22:52

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.