4

Using TeXlive 2016 with LuaLaTeX, but I think this is general. It concerns ordinary text, without math mode, floats, lists, or anything like that.

The problem: Different users provide blocks of plain text, with very minimal LaTeX markup. In particular, they know that \\ is used for a line break, and that \par or a blank line means new paragraph.

The user text is inserted into a macro, which processes the text. Problem: Some users put \\ at the end of their text. It is not supposed to be there. If the text ends without \\ (even if it ends with \par) then OK. But if it ends with \\ then an extra blank line is inserted.

Currently, this requires someone (not always me) to inspect the submitted text, and manually remove \\ if it appears at the end. My question: Is there a way to automatically remove \\ from the end of a block of text, before it is processed any further? Within LaTex, that is.

MWE:

% !TeX program = LuaLaTeX
% !TeX encoding = UTF-8
\documentclass{article}
\def\printTHIS{Well, not really all that dark.\\} % incorrect user input
\begin{document}
It was a dark and stormy night.\par
\printTHIS\par
And not really all that stormy, either.\par
\end{document}

I already searched and found a reference to vskip=\lastskip which did not work in this situation. Note: The skip between paragraphs is set to 0pt.

  • why have these documents got either \\ or \par both should be very rare in documents (except for \\ use in tables and math alignments) – David Carlisle Feb 3 '17 at 8:00
  • @DavidCarlisle The documents have them, because the users do not read instructions. – user103221 Feb 3 '17 at 16:36
  • \renewcommand\\{} – David Carlisle Feb 3 '17 at 16:36
  • @DavidCarlisle I suppose that simple solution would work. It would also remove intermediate \\ if the problem were more general. But since the user input is mingled with non-user input that does use \\, I'd have to set up groups to limit the scope, or something like that. The solution accepted below (especially with its general modifcation) seems to be best. – user103221 Feb 3 '17 at 16:41
5

I am not sure if this is an option for you, but one possibility is pass the user text to a "sanitizing" macro that removes \\ at the end of the text if it exists. You can do this using a "helper" macro that looks for the \\ and throws it away. For example,

\newcommand\printTHIS[1]{\CheckEndings#1\\@}
\def\CheckEndings#1\\#2@{#1}

So, \printTHIS passes the user text to \CheckEndings, together with \\@. The \CheckEndings macro expects two arguments that are delimited by \\ and @. If the user text does not end in \\ then, for the \CheckEndings macro, #1 is the users' text and #2 is empty, whereas if the text ends with \\ then #2 is \\. Either way, \CheckEndings throws the #2 away and just prints the (sanitized) text.

Here is a full MWE:

\documentclass{article}
\makeatletter
\newcommand\printTHIS[1]{\CheckEndings#1\\@}
\def\CheckEndings#1\\#2@{#1}
\makeatother

\begin{document}
It was a dark and stormy night.\par
\printTHIS{Well, not really all that dark.\\}\par % incorrect user input
\printTHIS{Well, not really dark at all.}\par % correct user input
And not really all that stormy, either.\par
\end{document}

EDIT

As pointed out in the comments, this approach fails for strings that have \\ embedded in them. Here is another approach using \SplitList from the xparse package that treats this case a little better:

\documentclass{article}
\usepackage{xparse}

\DeclareDocumentCommand\RemoveSlashes{>{\SplitList{\\}}m}
     {\ProcessList{#1}\PrintPieces}
\newcommand\PrintPieces[1]{#1 }

\begin{document}

  It was a dark and stormy night.\par
  \RemoveSlashes{Well, not really all that dark.\\}\par % incorrect user input
  \RemoveSlashes{Well, not really dark at all.}\par % correct user input
  \RemoveSlashes{Well, not really dark at all,\\ but not that light either}\par % correct user input
  \RemoveSlashes{Well, not dark,\\ and not  light either.\\}\par % correct user input
  And not really all that stormy, either.\par

\end{document}

The output is:

enter image description here

A possible criticism of this approach is that it ignores all of the embedded \\'s. If you wanted to print the embedded \\, except for the last one of course, then you can do this with the following variation of the ideas above:

\DeclareDocumentCommand\RemoveSlashes{>{\SplitList{\\}}m}
     {\let\piecesSep\relax% insert before each "piece" (nothing at start)
      \ProcessList{#1}\PrintPieces}
\newcommand\PrintPieces[1]{\ifx#1\empty\else\piecesSep #1\fi
      \def\piecesSep{\\}\fi% insert \\ after first piece
}

This will treat embedded strings like \\\\ as \\, which may not be what is wanted, but there is a limit as to how much you (or at least, I), can protect users from their own stupidity:)

  • Precisely solves the problem, as posed. That's what I had in mind. "Sanitize" is the key word, but it did not occur to me. – user103221 Feb 3 '17 at 3:35
  • Hm... And what if a user will put \\` in the middle of his text. The macro will drop the portion after \\`, which I guess would be unfortunate. – Sergei Golovan Feb 3 '17 at 5:36
  • @SergeiGolovan Thanks for mentioning this. . Yes, this is a potential problem. I was going to mention this but forgot. I don't see an easy way to fix this issue with my initial approach so I have added a second solution. – Andrew Feb 3 '17 at 6:20
  • @SergeiGolovan Yes, \\ in the middle will also be dropped. That limits the scope of the solution. In my specific case, it's OK, because \\ is forbidden in the middle (the user will notice the error before it gets to me). The specific problem involed putting \\ at the end when it should have been \par or nothing. I can see that a more general solution would be limited to the ending. The revision looks good. – user103221 Feb 3 '17 at 16:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy