tabular
我正在尝试使用循环将代表表行的文件输入到环境中,但在使用时遇到了麻烦input
。
这是我的代码的 MWE,没有使用循环。我有一些包含表格行的文件,我可以使用数字循环这些行,并且我\tables
使用存储这些表格的文件夹的路径定义命令。我使用csname
with来避免不可扩展的input
问题(当我以正常方式输入表格后立即添加时会导致一些问题)。input
\midrule
\begin{filecontents*}[overwrite]{Folder/r_1.tex}
A & B \\
C & D \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{Folder/r_2.tex}
1 & 2 \\
3 & 4 \\
\end{filecontents*}
\documentclass{article}
\usepackage{booktabs}
\newcommand{\tables}{Folder} %Path for tables
\begin{document}
\begin{tabular}{cc}
\toprule
\csname @@input\endcsname "\tables/r_1.tex"
\midrule
\csname @@input\endcsname "\tables/r_2.tex"
\bottomrule
\end{tabular}
\end{document}
我曾尝试使用 和 来实现这一点pgffor
,forloop
但都无济于事。以下是我尝试使用 实现的效果pgffor
:
\begin{tabular}{cc}
\midrule
\foreach \x in {1,...,2}{
\csname @@input\endcsname "\tables/r_\x.tex"
\midrule
}
\end{tabular}
上一个表无法编译。我尝试了一个更简单的版本,其中有常规的input
和,但没有使用booktabs
,但它也不起作用,即使代码在循环之外运行良好。
\begin{tabular}{cc}
\foreach \x in {1,...,2}{
\input{\tables/r_\x.tex}
}
\end{tabular}
有什么想法我可以做些什么来解决这个问题?
答案1
每个表格单元格本身都是一个范围。
并且每次迭代\foreach
都会打开其自己的本地范围。(pgfmanual.pdf,“88 重复的事情:Foreach 语句”部分说:“请注意,在每次执行 ⟨commands⟩ 时,⟨commands⟩ 都会放入一个 TeX 组中。”)
因此,表格单元格的作用域和迭代的作用域\foreach
会产生严重干扰:
\begin{tabular}{cc}
\midrule
\foreach \x in {1,...,2}{
\csname @@input\endcsname "\tables/r_\x.tex"
\midrule
}
\end{tabular}
就好像
\begin{tabular}{cc}
% Begin of scope of 1st table cell in 1st row
% Begin of scope of 1st foreach-iteration
A
% End of scope of 1st table cell in 1st row
&
[...]
您可以看到,例如,已找到第一行第一个表格单元格的范围结束,但第一个 foreach 迭代的范围尚未关闭。
您可以使用\foreach
-loop 来收集令牌寄存器中的内容:
\begin{filecontents*}[overwrite]{Folder/r_1.tex}
A & B \\
C & D \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{Folder/r_2.tex}
1 & 2 \\
3 & 4 \\
\end{filecontents*}
\documentclass{article}
\usepackage{booktabs, pgffor}
\newcommand{\tables}{Folder} %Path for tables
\newtoks\scratchtoks
\newcommand\globaladdtoscratchtoks[1]{%
\global\scratchtoks=\expandafter{\the\scratchtoks#1}%
}%
\begin{document}
\global\scratchtoks={}
\foreach \x in {1,...,2}{
\ifnum\x=1 \globaladdtoscratchtoks{\toprule}\fi
\expandafter\globaladdtoscratchtoks\expandafter{%
\csname @@input%
\expandafter \expandafter
\expandafter \endcsname
\expandafter \expandafter
\expandafter "%
\expandafter \tables
\expandafter /%
\expandafter r%
\expandafter_%
\x.tex"%
}%
\ifnum\x=2 %
\globaladdtoscratchtoks{\bottomrule}%
\else
\globaladdtoscratchtoks{\midrule}%
\fi
}%
%\showthe\scratchtoks
\begin{tabular}{cc}\the\scratchtoks\end{tabular}
\end{document}
如果您不愿意坚持使用 pgf \foreach
,而是定义自己的尾部递归循环(例如使用)\numexpr
,您可以执行以下操作:
\begin{filecontents*}[overwrite]{Folder/r_1.tex}
A & B \\
C & D \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{Folder/r_2.tex}
1 & 2 \\
3 & 4 \\
\end{filecontents*}
\documentclass{article}
\usepackage{booktabs}
\newcommand{\tables}{Folder} %Path for tables
\newcommand\inputloop[2]{%
\csname @\ifnum\numexpr(#1)\relax>\numexpr(#2)\relax
gobble\else firstofone\fi\endcsname{%
\csname @@input\endcsname "\tables/r_\the\numexpr(#1)\relax.tex"
\ifnum\numexpr(#1)\relax<\numexpr(#2)\relax \midrule \fi
\expandafter\inputloop\expandafter{\the\numexpr((#1)+1)\relax}{#2}%
}%
}%
\begin{document}
\begin{tabular}{cc}
\toprule
\inputloop{1}{2}%
\bottomrule
\end{tabular}
\end{document}
\inputloop
如果愿意,您可以按如下方式更改参数模式:
\inputloop{⟨lower bound for number-components of filenames⟩}
{⟨upper bound for number-components of filenames⟩}
{⟨file-path and/or filename-component at the left of the filename's number-component⟩}
{⟨filename-component at the right of the filename's number-component⟩}
{⟨tokens between \input-commands⟩}%
\begin{filecontents*}[overwrite]{Folder/r_1.tex}
A & B \\
C & D \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{Folder/r_2.tex}
1 & 2 \\
3 & 4 \\
\end{filecontents*}
\documentclass{article}
\usepackage{booktabs}
\newcommand{\tables}{Folder} %Path for tables
\newcommand\inputloop[5]{%
\csname @\ifnum\numexpr(#1)\relax>\numexpr(#2)\relax
gobble\else firstofone\fi\endcsname{%
\csname @@input\endcsname "#3\the\numexpr(#1)\relax#4"
\csname @\ifnum\numexpr(#1)\relax<\numexpr(#2)\relax
firstofone\else gobble\fi\endcsname{#5}%
\expandafter\inputloop\expandafter{\the\numexpr((#1)+1)\relax}{#2}{#3}{#4}{#5}%
}%
}%
\begin{document}
\begin{tabular}{cc}
\toprule
\inputloop{1}{2}{\tables/r_}{.tex}{\midrule}%
\bottomrule
\end{tabular}
\end{document}
答案2
这里我使用 的方法readarray
。请注意,为了方便起见,我更改了文件名以仅保留在工作目录中。
在这里,我展示如何循环遍历由
% LIST OF FILE IDENTIFIERS
\def\filelist{1,2,X}
在这种情况下,由于文件中已经包含表格格式,我只需要将文件内容读入\def
.
以下是 MWE:
\begin{filecontents*}[overwrite]{r_1.tex}
A & B \\
C & D \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{r_2.tex}
1 & 2 \\
3 & 4 \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{r_X.tex}
\today & ZZ \\
P & Q \\
\end{filecontents*}
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{booktabs, readarray,listofitems}
\newtoks\mytoks
\newcommand\addtotoks[1]{\global\mytoks\expandafter{\the\mytoks#1}}
\newcommand\xaddtotoks[1]{\expandafter\addtotoks\expandafter{#1}}
\readarraysepchar{}
\newcommand{\tables}{Folder} %Path for tables
% LIST OF FILE IDENTIFIERS
\def\filelist{1,2,X}
% READ FILE CONTENTS INTO VARIABLES NAMED \r_<identifier>
\readlist\myfiles{\filelist}
\foreachitem\z\in\myfiles[]{%
\def\tmp{\readdef{r_\z.tex}}
\expandafter\tmp\expandafter{\csname r_\z\endcsname}
}
\begin{document}
\begin{tabular}{cc}
\toprule
% ACCUMULATE TYPESET ARRAY TOKENS
\foreachitem\z\in\myfiles[]{%
\ifnum\zcnt=1\else\addtotoks{\midrule}\fi
\xaddtotoks{\csname r_\z\endcsname}%
}%
% SET THE TOKENS IN THE TABULAR
\the\mytoks
\bottomrule
\end{tabular}
\end{document}
如果希望避免将&
和\\
格式置于数据文件本身中,readarray
也可以处理这种情况。但是,在这种情况下,必须将文件信息读入二维数组,以便通过适当重新定义\typesetrowsepchar
和在单元格之间添加表格格式\typesetcolsepchar
。
\begin{filecontents*}[overwrite]{r_1.tex}
A, B
C, D
\end{filecontents*}
\begin{filecontents*}[overwrite]{r_2.tex}
1, 2
3, 4
\end{filecontents*}
\begin{filecontents*}[overwrite]{r_X.tex}
\today, ZZ
P, Q
\end{filecontents*}
\documentclass{article}
\usepackage{booktabs, readarray,listofitems}
\newtoks\mytoks
\newcommand\addtotoks[1]{\global\mytoks\expandafter{\the\mytoks#1}}
\newcommand\xaddtotoks[1]{\expandafter\addtotoks\expandafter{#1}}
\readarraysepchar{,}
\renewcommand\typesetrowsepchar{\\}
\renewcommand\typesetcolsepchar{&}
\newcommand{\tables}{Folder} %Path for tables
% LIST OF FILE IDENTIFIERS
\def\filelist{1,2,X}
% READ FILE CONTENTS INTO ARRAYS NAMED
% \myarray_<identifier>[<row>,<column>]
\readlist\myfiles{\filelist}
\foreachitem\z\in\myfiles[]{%
\def\tmp{\readdef{r_\z.tex}}
\expandafter\tmp\expandafter{\csname r_\z\endcsname}
\expandafter\readarray\csname r_\z\expandafter\endcsname
\csname myarray\z\endcsname[-,\ncols]
}
\begin{document}
\begin{tabular}{cc}
\toprule
% ACCUMULATE TYPESET ARRAY TOKENS
\foreachitem\z\in\myfiles[]{%
\ifnum\zcnt=1\else\addtotoks{\\\midrule}\fi
\addtotoks{\expandafter\typesetarray\csname myarray}%
\xaddtotoks{\z\endcsname}%
}%
% SET THE TOKENS IN THE TABULAR
\the\mytoks\\
\bottomrule
\end{tabular}
\end{document}
答案3
使用 OpTeX 时没有问题,因为OpTeX 独立于 TeX 组运行并且它们是可扩展的\fornum
。\foreach
\createfile {r_1.tex}
A & B \cr
C & D \cr
\endfile
\createfile {r_2.tex}
1 & 2 \cr
3 & 4 \cr
\endfile
\def\toprule{\crcr\noalign{\hrule height1pt}}
\let\bottomrule=\toprule
\def\midrule{\crcr\noalign{\hrule}}
\table{cc}{
\toprule
\fornum 1..2 \do{\input r_#1 \ifnum#1<2 \midrule \else \bottomrule \fi}
}
\bye
答案4
将文件加载到变量中,将它们放在一起并立即传送,并\midrule
在它们之间进行。
文件加载已经完成,\file_get:nnNTF
因此我们也可以防止文件丢失。
\begin{filecontents*}[overwrite]{Folder/r_1.tex}
A & B \\
C & D \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{Folder/r_2.tex}
1 & 2 \\
3 & 4 \\
\end{filecontents*}
\documentclass{article}
\usepackage{booktabs}
\ExplSyntaxOn
\NewDocumentCommand{\maketablefromfiles}{O{.}m}
{% #1 = optional path, #2 = list of file names
\suarez_maketable:nn { #1 } { #2 }
}
\seq_new:N \l__suarez_maketable_body_seq
\tl_new:N \l__suarez_maketable_tmp_tl
\cs_new_protected:Nn \suarez_maketable:nn
{
\seq_clear:N \l__suarez_maketable_body_seq
\clist_map_inline:nn { #2 }
{
\file_get:nnNTF { #1/##1 } {} \l__suarez_maketable_tmp_tl
{% file exists
\seq_put_right:NV \l__suarez_maketable_body_seq \l__suarez_maketable_tmp_tl
}
{% file doesn't exist
\msg_error:nnn { suarez/maketable } { file-not-exist } { ##1 }
\seq_put_right:Nn \l__suarez_maketable_body_seq { \\ }
}
}
\seq_use:Nn \l__suarez_maketable_body_seq { \midrule }
}
\msg_new:nnnn { suarez/maketable } { file-not-exist }
{
Non~existing~file~#1
}
{
The~file~you~requested~doesn't~exist.~Added~\tl_to_str:n { \\ }~to~avoid~errors
}
\ExplSyntaxOff
\newcommand{\tables}{Folder}
\begin{document}
% with the explicit path
\begin{tabular}{cc}
\toprule
\maketablefromfiles[Folder]{r_1,r_2}
\bottomrule
\end{tabular}
\bigskip
% with the macro for the path; also error shown
\begin{tabular}{cc}
\toprule
\maketablefromfiles[\tables]{r_1,r_2,r_3}
\bottomrule
\end{tabular}
\end{document}
第二个示例显示您可以在“path”参数中使用宏。我还展示了如果您请求不存在的文件会发生什么。当然,如果您r_3
在第二个参数中删除,则输出与第一个示例相同。
控制台上显示的错误:
! Package suarez/maketable Error: Non existing file r_3
For immediate help type H <return>.
...
l.66 \maketablefromfiles[\tables]{r_1,r_2,r_3}
? h
The file you requested doesn't exist. Added \\ to avoid errors
?
略有不同的版本,其中各部分之间的分离是可选的(默认\midrule
)。
\begin{filecontents*}[overwrite]{Folder/r_1.tex}
A & B \\
C & D \\
\end{filecontents*}
\begin{filecontents*}[overwrite]{Folder/r_2.tex}
1 & 2 \\
3 & 4 \\
\end{filecontents*}
\documentclass{article}
\usepackage{booktabs}
\ExplSyntaxOn
\NewDocumentCommand{\maketablefromfiles}{O{.}mO{\midrule}}
{% #1 = optional path, #2 = list of file names, #3 = optional separator
\suarez_maketable:nnn { #1 } { #2 } { #3 }
}
\seq_new:N \l__suarez_maketable_body_seq
\tl_new:N \l__suarez_maketable_tmp_tl
\cs_new_protected:Nn \suarez_maketable:nnn
{
\seq_clear:N \l__suarez_maketable_body_seq
\clist_map_inline:nn { #2 }
{
\file_get:nnNTF { #1/##1 } {} \l__suarez_maketable_tmp_tl
{% file exists
\seq_put_right:NV \l__suarez_maketable_body_seq \l__suarez_maketable_tmp_tl
}
{% file doesn't exist
\msg_error:nnn { suarez/maketable } { file-not-exist } { ##1 }
\seq_put_right:Nn \l__suarez_maketable_body_seq { \\ }
}
}
\seq_use:Nn \l__suarez_maketable_body_seq { #3 }
}
\msg_new:nnnn { suarez/maketable } { file-not-exist }
{
Non~existing~file~#1
}
{
The~file~you~requested~doesn't~exist.~Added~\tl_to_str:n { \\ }~to~avoid~errors
}
\ExplSyntaxOff
\newcommand{\tables}{Folder}
\begin{document}
% with the explicit path
\begin{tabular}{cc}
\toprule
\maketablefromfiles[Folder]{r_1,r_2}
\bottomrule
\end{tabular}
\bigskip
% with the macro for the path
\begin{tabular}{cc}
\toprule
\maketablefromfiles[\tables]{r_1,r_2}[\addlinespace]
\bottomrule
\end{tabular}
\end{document}