这个问题引出了包中的一个新功能:
datatool
\DTLgdeletedb
在 (v2.13) 及更高版本中可用。
我正在尝试使用\foreach
循环来迭代几个项目。每次迭代的步骤\ExtractData
如下:
- 将数据加载到
mydb
。 - 提取适当的数据。
- 删除
mydb
。
这在 之外工作得很好\foreach
。但如果在 中使用\foreach
,则似乎数据库未被删除,并且任何后续尝试创建具有相同名称的新数据库都会失败,并显示以下内容:
包
datatool
错误:数据库“myDB”已存在。
笔记:
- 下面的 MWE 示例表明,数据库访问在 之外
\foreach
和 在 之内都可以正常工作。第一的在 内调用\foreach
。 - 发生故障仅有的
\ExtractData
如果在 中的 use 之后尝试使用\foreach
。因此取消注释任何注释块都将显示失败。 - 在有人问我为什么关闭并重新打开同一个数据库之前,在我的实际使用中,打开的数据文件对于每个成员都是不同的
\foreach
。只是数据库的名称相同。我想我每次都可以创建一个新名字,但我真的很想知道实际的问题是什么。
参考:
- 这个问题Datatool:无法在嵌套循环“foreach”中使用 \DTLreplaceentryforrow似乎有点相关,但由于我没有使用
\DTLforeach
来遍历数据库,所以我认为它对我没有帮助。
代码:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{foo.dat}
Smith, John, 1977-05-04
Doe, Jane, 1980-05-04
\end{filecontents*}
\usepackage{xstring}
\usepackage{pgffor}
\usepackage{datatool}
\newcommand{\ExtractData}[3]{% #1=file name #2=row, #3=col
\DTLloaddb[noheader,keys={LastName, FirstName, DOB}]{myDB}{#1}%
\IfEq{\DTLrowcount{myDB}}{0}{%
\def\Value{NO VALUE}
}{%
\DTLgetvalue{\Value}{myDB}{#2}{#3}%
}%
\DTLdeletedb{myDB}%
\Value%
}
\begin{document}
\section{Works}
\ExtractData{foo.dat}{1}{2}
\ExtractData{foo.dat}{1}{1}
\section{Works in foreach (one element)}
\foreach \x in {2}{
\ExtractData{foo.dat}{1}{\x}
}
\section{Does NOT work subsequent to foreach (one element)}
%\ExtractData{foo.dat}{1}{1}
%\foreach \x in {1}{
% \ExtractData{foo.dat}{1}{\x}
%}
\section{Does NOT works in foreach (more than one element)}
%\foreach \x in {2,1}{
% \ExtractData{foo.dat}{1}{\x}\par\noindent
%}
\end{document}
答案1
\foreach
在组内工作,因此数据库的删除只是本地的。定义一个“全局”删除命令\DTLgdeletedb
并使用它。
\makeatletter
\newcommand*{\DTLgdeletedb}[1]{%
\DTLifdbexists{#1}%
{%
\dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do
{%
\global\expandafter\let\csname dtl@ci@#1@\@dtl@key\endcsname\undefined
}%
\global\expandafter\let\csname dtldb@#1\endcsname\undefined
\global\expandafter\let\csname dtlkeys@#1\endcsname\undefined
\global\expandafter\let\csname dtlrows@#1\endcsname\undefined
\global\expandafter\let\csname dtlcols@#1\endcsname\undefined
}%
{%
\PackageError{Can't delete database `#1':
database doesn't exist}{}{}%
}%
}
\makeatother
它与命令相同\DTLdeletedb
,但带有\global
前缀。我担心大量使用这种方法会污染保存堆栈;请注意。
答案2
我无法回答这个问题,但我想说的是循环\@for
运行良好:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{foo.dat}
Smith, John, 1977-05-04
Doe, Jane, 1980-05-04
\end{filecontents*}
\usepackage{xstring}
\usepackage{pgffor}
\usepackage{datatool}
\newcommand{\ExtractData}[3]{% #1=file name #2=row, #3=col
\DTLloaddb[noheader,keys={LastName, FirstName, DOB}]{myDB}{#1}%
\IfEq{\DTLrowcount{myDB}}{0}{%
\def\Value{NO VALUE}
}{%
\DTLgetvalue{\Value}{myDB}{#2}{#3}%
}%
\DTLdeletedb{myDB}%
\Value%
}
\makeatletter
\let\myloop\@for
\makeatother
\begin{document}
\section{Works}
\ExtractData{foo.dat}{1}{2}
\ExtractData{foo.dat}{1}{1}
\section{Works in foreach (one element)}
\myloop\xx:={2}\do{%
\ExtractData{foo.dat}{1}{\xx}%
}
\section{Does NOT work subsequent to foreach (one element)}
\ExtractData{foo.dat}{1}{1}
\myloop\xx:={1}\do{%
\ExtractData{foo.dat}{1}{\xx}%
}
\section{Does NOT works in foreach (more than one element)}
\myloop\xx:={2,1}\do{%
\ExtractData{foo.dat}{1}{\xx}\par\noindent%
}
\end{document}