Datatool gobbling spaces

This does not fix the datatool bug, but rather shows an alternate approach using readarray. It creates an array \Sentence[<i>,<j>], where i and j are the row and column of the \Sentence array.

\documentclass{article}
\usepackage{readarray,tikz}
\begin{filecontents*}{\jobname.csv}
The child played a new game.,He played it three times with his friends.,He loved the game.
I visited my childhood home last week.,It's just as I remembered it.,My house has always been white.
It's just as I remembered it.,I visited my childhood home last week.,My house has always been white.
\end{filecontents*}
\readarraysepchar{,}
\begin{document}
\readdef{\jobname.csv}\Sentences
\readarray\Sentences\Sentence[-,\ncols]
\foreach\x in {1,2,...,\SentenceROWS}
  {\foreach\y in {1,2,...,\SentenceCOLS}{\Sentence[\x,\y]\par}}
\end{document}

enter image description here


I propose a different patch than Nicola’s.

\RequirePackage{filecontents}
\begin{filecontents}{\jobname.csv}
Sentence1,Sentence2,Sentence3
The child played a new game.,He played it three times with his friends.,He loved the game.
I visited my childhood home last week.,It's just as I remembered it.,My house has always been white.
It's just as I remembered it.,I visited my childhood home last week.,My house has always been white.
{}A visited my childhood home last week.,It's just as I remembered it.,My house has always been white.
{Bbb} visited my childhood home last week.,It's just as I remembered it.,My house has always been white.
X,X,X
X
\end{filecontents}
\documentclass{article}
\usepackage{datatool}

\makeatletter
\let\saved@dtl@starttrim\@dtl@starttrim
\long\def\@dtl@starttrim#1{%
  \def\fix@dtl@starttrim@first{#1}%
  \futurelet\next\fix@dtl@starttrim@second
}
\def\fix@dtl@starttrim@second{%
  \if\noexpand\next\@sptoken
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\expandafter\saved@dtl@starttrim\expandafter{\fix@dtl@starttrim@first}{}}%
  {\expandafter\saved@dtl@starttrim\expandafter{\fix@dtl@starttrim@first}}%
}
\makeatother


\DTLloaddb{sentences}{\jobname.csv}
\begin{document}
\DTLforeach{sentences}{%
\sOne=Sentence1,\sTwo=Sentence2,\sThree=Sentence3}
{%
\sOne\par
\sTwo\par
\sThree\par\kern1pt\hrule\kern1pt
}
\end{document}

The trimming macro checks whether the first token is followed by a space, but absorbing just one token (or braced group). It takes different actions according to whether the token is a space or not.

enter image description here


This bug has now been fixed. If you encounter it, make sure you have the latest version of datatool.


Original answer

The problem is with \dtl@trim which is supposed to trim the trailing space at the end of each line (caused by the end of line character). It's also supposed to discard the terminating \par that occurs on the final \read before the end of file is reached.

I think the following patch should fix the problem (but I need to test further to make sure it doesn't cause any unwanted side-effects). The argument of \dtl@trim is always a control sequence (set by \read for \DTLloaddb).

\makeatletter
\renewcommand{\dtl@trim}[1]{%
  \if#1\par
    \def\@dtl@trmstr{}%
  \else
    \expandafter\@dtl@start@trim#1\@dtl@end@trim
  \fi
  \let#1=\@dtl@trmstr
}

\def\@dtl@start@trim#1 \@dtl@end@trim{%
 \def\@dtl@trmstr{#1}%
}

\makeatother

Complete MWE:

\begin{filecontents}{\jobname.csv}
Sentence1,Sentence2,Sentence3
The child played a new game.,He played it three times with his friends.,He loved the game.
I visited my childhood home last week.,It's just as I remembered it.,My house has always been white.
It's just as I remembered it.,I visited my childhood home last week.,My house has always been white.
\end{filecontents}
\documentclass{article}
\usepackage{datatool}

\makeatletter
\renewcommand{\dtl@trim}[1]{%
  \if#1\par
    \def\@dtl@trmstr{}%
  \else
    \expandafter\@dtl@start@trim#1\@dtl@end@trim
  \fi
  \let#1=\@dtl@trmstr
}

\def\@dtl@start@trim#1 \@dtl@end@trim{%
 \def\@dtl@trmstr{#1}%
}

\makeatother

\DTLloaddb{sentences}{\jobname.csv}
\begin{document}
\DTLforeach{sentences}{%
\sOne=Sentence1,\sTwo=Sentence2,\sThree=Sentence3}
{%
\sOne\par
\sTwo\par
\sThree\par
}
\end{document}

image of document