我遇到了一个奇怪的问题datatool
。如果一行的第一列的第一个字符后面紧跟着一个空格,那么这个空格就会被吞掉。是我做错了什么,还是这是一个错误?
\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}
\DTLloaddb{sentences}{\jobname.csv}
\begin{document}
\DTLforeach{sentences}{%
\sOne=Sentence1,\sTwo=Sentence2,\sThree=Sentence3}
{%
\sOne\par
\sTwo\par
\sThree\par
}
\end{document}
这是输出。请注意,CSV 文件第 1 列中的句子(用红色箭头标记)有被吞噬的空格,但第 2 列中的完全相同的句子(用蓝色箭头标记)没有被吞噬的空格。
答案1
此错误现已修复。如果您遇到此问题,请确保您拥有最新版本的datatool
。
原始答案
问题在于,\dtl@trim
它应该修剪每行末尾的尾随空格(由行尾字符引起)。它还应该丢弃在到达文件末尾之前\par
发生在最后的终止符。\read
我认为以下补丁应该可以修复该问题(但我需要进一步测试以确保它不会引起任何不必要的副作用)。的参数\dtl@trim
始终是一个控制序列(由\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
完成 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}
答案2
这并不能修复datatool
错误,而是展示了使用 的替代方法readarray
。它创建一个数组\Sentence[<i>,<j>]
,其中i
和j
是数组的行和列\Sentence
。
\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}
答案3
我建议使用与尼古拉不同的补丁。
\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}
修剪宏检查第一个标记后面是否跟着空格,但只吸收一个标记(或括号组)。它根据标记是否为空格采取不同的操作。