我想用 存储表格行\addtocontents
,然后用 从这些条目生成一个表格\@starttoc
。因为\@starttoc
使用\begingroup
和它会导致表格出现问题(!额外 },或被遗忘的 \endgroup)。所以我尝试基于 的定义(没有组\endgroup
宏)定义我自己的命令,现在实际上可以编译:\starttoc
\@starttoc
\documentclass{article}
\makeatletter
\newcommand\addEntry[2]{#1\\}
\newcommand\mystarttoc[1]{\@input{\jobname.#1}\if@filesw\expandafter\newwrite\csname tf@#1\endcsname\immediate\openout\csname tf@#1\endcsname\jobname.#1\relax\fi}
\begin{document}
\begin{tabular}{|l|l|}
\addEntry{\textbf{ID}}{\textbf{Description}}
\mystarttoc{damageClassA} % summarize damages with class A
%\mystarttoc{damageClassA}\\ % would not work cause damageClassA contains multiple table lines
\mystarttoc{damageClassB} % summarize damages with class B
\mystarttoc{damageClassC} % should not extend table cause there are no class C damages in this MWE
\end{tabular}
\addtocontents{damageClassA}{\addEntry{A-1}{damage1 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-2}{damage2 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-X}{damage...X with classification A}}
\addtocontents{damageClassB}{\addEntry{B-1}{damage1 with classification B}}
\makeatother
\end{document}
但是,starttoc 宏的 if 子句似乎引入了一些多余的空格,导致 foo4 行未对齐,并且出现了多余的空表格行:
能以某种方式防止这种情况发生吗?还是我应该使用完全不同的方法?LaTeX2e 语法比 expl 语法更受欢迎。
更新 这实际上是来自的一个后续问题如何在文档开头自动生成数据摘要?我更新了我的 MWE,希望我的意图更加清晰。
我想在一个文件中汇总 0..X 类 A 损害damageClassA
。B 类和 C 类也一样。因此一次只有 3 个文件。但每个文件应该能够处理多个表行。
最终的表格实际上会更复杂一些。因此,使用表格以外的其他东西来获得当前的视觉效果也不幸不是一个解决方案。
答案1
您可以使用 来隐藏不需要的空格\ignorespaces
。为了避免出现空行,第一个条目必须与以下内容不同。以下假设您只有一个这样的表格。
\documentclass{article}
\makeatletter
\newcommand\addEntry[2]{#1\global\let\addEntry\addEntrycont}
\newcommand\addEntrycont[2]{\\#1}
\newcommand\mystarttoc[1]{%
\@input{\jobname.#1}%
\if@filesw\expandafter\newwrite\csname tf@#1\endcsname\immediate\openout\csname tf@#1\endcsname\jobname.#1\relax\fi
\ignorespaces}
\makeatother
\begin{document}
\begin{tabular}{|l|l|}
\addEntry{\textbf{ID}}{\textbf{Description}}
\mystarttoc{damageClassA} % summarize damages with class A
%\mystarttoc{damageClassA}\\ % would not work cause damageClassA contains multiple table lines
\mystarttoc{damageClassB} % summarize damages with class B
\mystarttoc{damageClassC} % should not extend table cause there are no class C damages in this MWE
\end{tabular}
\addtocontents{damageClassA}{\addEntry{A-1}{damage1 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-2}{damage2 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-X}{damage...X with classification A}}
\addtocontents{damageClassB}{\addEntry{B-1}{damage1 with classification B}}
\makeatother
\end{document}
如果您知道您将始终有一个标题行,那么您也可以执行以下操作:
\documentclass{article}
\makeatletter
\newcommand\addTitleEntry[2]{#1}
\newcommand\addEntry[2]{\\#1}
\newcommand\mystarttoc[1]{%
\@input{\jobname.#1}%
\if@filesw\expandafter\newwrite\csname tf@#1\endcsname\immediate\openout\csname tf@#1\endcsname\jobname.#1\relax\fi
\ignorespaces}
\makeatother
\begin{document}
\begin{tabular}{|l|l|}
\addTitleEntry{\textbf{ID}}{\textbf{Description}}
\mystarttoc{damageClassA} % summarize damages with class A
%\mystarttoc{damageClassA}\\ % would not work cause damageClassA contains multiple table lines
\mystarttoc{damageClassB} % summarize damages with class B
\mystarttoc{damageClassC} % should not extend table cause there are no class C damages in this MWE
\end{tabular}
\addtocontents{damageClassA}{\addEntry{A-1}{damage1 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-2}{damage2 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-X}{damage...X with classification A}}
\addtocontents{damageClassB}{\addEntry{B-1}{damage1 with classification B}}
\makeatother
\end{document}
答案2
我建议采用略有不同的方法。\printsummary
定义所需的类别,使用上次运行收集的数据生成表格。接下来打开“toc”文件。
表体在排版之前使用 进行填充\CatchFileDef
,因此我们可以控制文件是否为空。
\documentclass{article}
\usepackage{catchfile}
\makeatletter
\newcommand\addEntry[2]{#1\\}
\newcommand{\printsummary}[1]{%
\def\class@summary{}%
\@for\next:=#1\do{%
\CatchFileDef\temp{\jobname.\next}{}%
\ifx\temp\@empty
\else
\edef\class@summary{%
\unexpanded\expandafter{\class@summary}%
\unexpanded\expandafter{\temp}%
}%
\fi
}%
\begin{tabular}{|l|l|}
\hline
\addEntry{\textbf{ID}}{\textbf{Description}}
\hline
\class@summary
\hline
\end{tabular}
% now open the files
\if@filesw
\@for\next:=#1\do{%
\expandafter\newwrite\csname tf@\next\endcsname
\immediate\openout\csname tf@\next\endcsname\jobname.\next\relax
}%
\fi
}
\makeatother
\begin{document}
\printsummary{damageClassA,damageClassB,damageClassC}
\addtocontents{damageClassA}{\addEntry{A-1}{damage1 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-2}{damage2 with classification A}}
\addtocontents{damageClassA}{\addEntry{A-X}{damage...X with classification A}}
\addtocontents{damageClassB}{\addEntry{B-1}{damage1 with classification B}}
\end{document}
另一种方法不需要任何辅助文件,可以避免事先定义类。它只是假设第一个参数\addentry
是大写字母。
该命令\addentry
在文件中写入适当的行.aux
。当.aux
在文档开头读取文件时,条目将填充一个序列。该命令\printsummary
将根据第一个参数对序列进行排序(但不修改同一类中条目的顺序)并打印表格。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\printsummary}{}
{
\cryptkeeper_summary_print:
}
\NewDocumentCommand{\addentry}{mmm}
{
\iow_now:cn { @auxout } { \summaryentry{#1}{#2}{#3} }
}
\NewDocumentCommand{\summaryentry}{mmm}
{
\seq_gput_right:Nn \g_cryptkeeper_summary_items_seq { {#1}{#2}{#3} }
}
\seq_new:N \g_cryptkeeper_summary_items_seq
\cs_new_protected:Nn \cryptkeeper_summary_print:
{
% sort the sequence based on the first item part
\seq_gsort:Nn \g_cryptkeeper_summary_items_seq
{
\int_compare:nTF { \__cryptkeeper_summary_sort:nnn ##1 > \__cryptkeeper_summary_sort:nnn ##2 }
{
\sort_return_swapped:
}
{
\sort_return_same:
}
}
\begin{tabular}{|l|l|}
\hline
\textbf{ID} & \textbf{Description} \\
\hline
\seq_map_function:NN \g_cryptkeeper_summary_items_seq \cryptkeeper_summary_print_entry:n
\hline
\end{tabular}
}
\cs_new:Nn \__cryptkeeper_summary_sort:nnn
{
\int_from_alph:n { #1 }
}
\cs_new_protected:Nn \cryptkeeper_summary_print_entry:n
{
\__cryptkeeper_summary_print_entry:nnn #1
}
\cs_new_protected:Nn \__cryptkeeper_summary_print_entry:nnn
{
#1-#2 & #3 \\
}
\ExplSyntaxOff
\begin{document}
\printsummary
\addentry{A}{1}{damage1 with classification A}
\addentry{A}{2}{damage2 with classification A}
\addentry{B}{1}{damage1 with classification B}
\addentry{A}{X}{damage...X with classification A}
\end{document}
输出与以前相同。
答案3
更新
既然您愿意尝试新方法,我将使用该datatool
包提供基于数据库的方法。
首先创建数据库并加载来自.cvs
文件的数据。
主命令\DTLforeach
允许您遍历数据库,检索每一行并执行任务。例如,使用一些列来完成表格。(第 2 节)
更有趣的是,可以根据标准选择行。(第 3 节)
在第 4 部分中,自定义命令\Desc {ID}
将检索相应的描述。
\documentclass[a4paper,12pt]{article}
\usepackage{datatool}
% raw data
\begin{filecontents*}[overwrite]{damagesclass.csv}
"Type", "ID", "Description"
A, A-1, damage1 with classification A
A, A-2, damage2 with classification A
A, A-X, damage ... X with classification A
B, B-1, damage1 with classification B
\end{filecontents*}
% Creates a new database named damages
% and fills it with the data
% from the CSV (comma-separated value) damagesclass.csv
\DTLloaddb{damages}{damagesclass.csv}
\begin{document}
\section{Show all the data base content}
\DTLdisplaydb{damages} % show all the content
\section{Table of selected columns (\#2 and \#3)}
\renewcommand{\arraystretch}{1.8}
\noindent\begin{tabular}{|c| l |}
\hline
{\bfseries ID} & {\bfseries Description}
\DTLforeach{damages}{\Type=Type,\ID=ID, \Description=Description}
{ \\ \ID &\Description }% display selected file content
\\ \hline
\end{tabular}
\section{Table of selected columns and selected rows (Type =A)}
\noindent\begin{tabular}{|c| l |}
\hline
{\bfseries ID} & {\bfseries Description}
\DTLforeach[\DTLiseq{\Type}{A}]{damages}{\Type=Type,\ID=ID, \Description=Description}
{\DTLiffirstrow{\\ \hline}{\\} \ID &\Description }% display selected file content
\\ \hline
\end{tabular}
\section{Find a single cell}
To qualify it required to have a \emph{\DTLfetch{damages}{ID}{A-2}{Description}}.
\end{document}