在编译期间生成 LaTeX 表格代码

在编译期间生成 LaTeX 表格代码

我使用 LaTeX 进行脑成像 (fMRI) 的科学报告。我有一个tabularLaTeX 数组,其中包含相当多的行和列,它们都是大脑区域,并且在每个相交的单元格中都有一些有关它们连接的数据。

此数组的内容tabular是使用命令加载的另一个 .tex 文件中单独定义的\input。在此另一个 .tex 文件中,数组的每个单元格的内容tabular使用数百个\newcommand命令单独定义。数组中除了这些命令tabular外没有其他内容。数组位于内部以允许对单元格值进行一些基本计算(尽管这不是必需的)。到目前为止一切正常。\newcommandtabular\begin{spreadtab}

因此,\newcommand定义如下:

\newcommand{\origREGIONONEdestREGIONONE}{ NA } % NA for cells on the diagonal.
\newcommand{\origREGIONONEdestREGIONTWO}{ - } % this is the default case.

...

\newcommand{\origREGINOTWOdestREGIONTWO}{ NA }
\newcommand{\origREGIONTWOdestREGIONONE}{ \ref{Spielberg1981} }
\newcommand{\origREGIONTWOdestREGIONTHREE}{ bilateral \ref{Cameron1989} }

...

\newcommand所有列 x 行交叉点都有一个特定的定义。

数组代码tabular如下所示(3x3 的示例,但实际上它大于 20x20):

\tiny
\begin{table}
    \scalebox{0.6}{
        \begin{spreadtab}{{tabular}{*{3}{c}}}
            \hline
            \to/from :={} & REGIONONE :={} & REGIONTWO :={} & REGIONTHREE :={} \\
            \hline
            to REGIONONE :={} & \origREGIONONEdestREGIONONE :={} & \origREGIONTWOdestREGIONONE :={} &\origREGIONTHREEdestREGIONONE :={} \\
            to REGIONTWO :={} & \origREGIONONEdestREGIONTWO :={} & \origREGIONTWOdestREGIONTWO :={} &\origREGIONTHREEdestREGIONTWO :={} \\
            to REGIONTHREE :={} & \origREGIONONEdestREGIONTHREE :={} & \origREGIONTWOdestREGIONTHREE :={} &\origREGIONTHREEdestREGIONTHREE :={} \\
            \hline
        \end{spreadtab}
    } % end scalebox
    \caption{A table of connections between brain regions 1, 2 & 3}
    \begin{enumerate}
        \item \cite{Spielberg1981}\label{Spielberg1981}
        \item \cite{Cameron1989}\label{Cameron1989}
    \end{enumerate}
\end{table}
\normalsize

现在我想要的是能够tabular根据列表或字符串数​​组(或使用任何可能的数据类型)动态生成类似的定义:

在 MATLAB 语法中它将是:ListOfBrainRegions = { 'BRAINREGIONABC', 'BRAINREGIONDEF', 'BRAINREGIONXYZ' }

在 Python 语法中:ListOfBrainRegions = [ 'BRAINREGIONABC', 'BRAINREGIONDEF', 'BRAINREGIONXYZ' ]

列表或数组将被转换成如下代码(如果出现问题spreadtab则不转换):spreadtab

            \hline
            \to/from :={} & REGIONABC :={} & REGIONDEF :={} & REGIONXYZ :={} \\
            \hline
            to REGIONABC :={} & \origREGIONABCdestREGIONABC :={} & \origREGIONDEFdestREGIONABC :={} &\origREGIONXYZdestREGIONABC :={} \\
            to REGIONDEF :={} & \origREGIONABCdestREGIONDEF :={} & \origREGIONDEFdestREGIONDEF :={} &\origREGIONXYZdestREGIONDEF :={} \\
            to REGIONXYZ :={} & \origREGIONABCdestREGIONXYZ :={} & \origREGIONDEFdestREGIONXYZ :={} &\origREGIONXYZdestREGIONXYZ :={} \\
            \hline

那么,我应该如何ListOfBrainRegions在 LaTeX 中定义?然后如何在编译 .tex 文件时生成 LaTeX 代码?如果我使用其他编程语言(例如 MATLAB、Common Lisp 或 awk)进行编程,则任务(生成程序代码)一点也不难。似乎 LaTeX 没有内置数组、if... elseif...else命令forwhile循环,尽管某些软件包提供了一些附加功能。那么,如何实现呢?或者,我应该使用哪些 LaTeX 命令、软件包和/或额外工具来完成这项任务?

感谢您的任何帮助 :)

答案1

实际上,LaTeX 格式确实有循环\@tfor等,但在表格中,TeX 处于有点微妙的状态,所以在这里我只使用普通扩展。

在此处输入图片描述

\documentclass{article}


\def\listheadings{%
\expandafter\xlistheadings\regionlist,\relax,}

\def\xlistheadings#1,{%
\ifx\relax#1%
\expandafter\\%
\else
&\textbf{#1}%
\expandafter\xlistheadings
\fi}

\def\listbody{%
\expandafter\xlistbody\regionlist,\relax,}

\def\xlistbody#1,{%
\ifx\relax#1%
\else
\textbf{#1}%
\gdef\thisrow{#1}%
\expandafter\xlistdata\regionlist,\relax,%
\expandafter\xlistbody
\fi}


\def\xlistdata#1,{%
\ifx\relax#1%
\expandafter\\%
\else
&\csname origREGION\thisrow destREGION#1\endcsname
\expandafter\xlistdata
\fi}


\def\preamble{\expandafter\xpreamble\regionlist,\relax,}
\def\xpreamble#1,{%
\ifx\relax#1%
\else
c|%
\expandafter\xpreamble
\fi}

\def\tablestart{%
\edef\temp{\noexpand\begin{tabular}{|c|\preamble}}%
\temp}

\begin{document}

\newcommand\regionlist{ONE,TWO,THREE}

\def\origREGIONONEdestREGIONONE{1/1}
\def\origREGIONONEdestREGIONTWO{1/2}
\def\origREGIONONEdestREGIONTHREE{1/3}

\def\origREGIONTWOdestREGIONONE{2/1}
\def\origREGIONTWOdestREGIONTWO{2/2}
\def\origREGIONTWOdestREGIONTHREE{2/3}

\def\origREGIONTHREEdestREGIONONE{3/1}
\def\origREGIONTHREEdestREGIONTWO{3/2}
\def\origREGIONTHREEdestREGIONTHREE{3/3}


\tablestart
\hline
\listheadings
\hline
\listbody
\hline
\end{tabular}

\end{document}

答案2

以下解决方案expl3展示了该语言的一些优良特性:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\generatetable}{m}{\nrz_generate_table:n {#1}}

\seq_new:N \l_nrz_head_seq
\tl_new:N \l_nrz_preamble_tl
\tl_new:N \l_nrz_header_tl
\tl_new:N \l_nrz_body_tl

\cs_new_protected:Npn \nrz_generate_table:n #1
 {
  \seq_set_split:Nnn \l_nrz_head_seq { , } { #1 }
  \nrz_generate_table_data:
  \nrz_output_table:
 }

\cs_new_protected:Npn \nrz_generate_table_data:
 {
  \tl_set:Nn \l_nrz_preamble_tl { | c | }
  \tl_clear:N \l_nrz_header_tl
  \tl_clear:N \l_nrz_body_tl
  \seq_map_inline:Nn \l_nrz_head_seq
   {
    \tl_put_right:Nn \l_nrz_preamble_tl { c | }
    \tl_put_right:Nn \l_nrz_header_tl { & \textbf{ ##1 } }
    \tl_put_right:Nn \l_nrz_body_tl { \textbf{ ##1 } } % first col
    \seq_map_inline:Nn \l_nrz_head_seq % other cols
     {
      \tl_put_right:Nn \l_nrz_body_tl { & \use:c { origREGION ##1 destREGION ####1 } }
     }
    \tl_put_right:Nn \l_nrz_body_tl { \\ }
   }
  \tl_put_right:Nn \l_nrz_header_tl { \\ }
 }
\cs_new_protected:Npn \nrz_output_table:
 {
  \begin{tabular}{ \tl_use:N \l_nrz_preamble_tl }
  \hline
  \tl_use:N \l_nrz_header_tl
  \hline
  \tl_use:N \l_nrz_body_tl
  \hline
  \end{tabular}
 }
\ExplSyntaxOff

\begin{document}

\def\origREGIONONEdestREGIONONE{1/1}
\def\origREGIONONEdestREGIONTWO{1/2}
\def\origREGIONONEdestREGIONTHREE{1/3}

\def\origREGIONTWOdestREGIONONE{2/1}
\def\origREGIONTWOdestREGIONTWO{2/2}
\def\origREGIONTWOdestREGIONTHREE{2/3}

\def\origREGIONTHREEdestREGIONONE{3/1}
\def\origREGIONTHREEdestREGIONTWO{3/2}
\def\origREGIONTHREEdestREGIONTHREE{3/3}

\generatetable{ONE,TWO,THREE}

\end{document}

表主体由一个映射函数构建,使用相同的映射序列!

首先,我们从作为参数传递给 的列表中构建序列\generatetable;然后我们继续使用这样获得的序列构建表格前言(以 开始|c|,并在每一步添加c|)、表格标题(& <string>在每一步添加,最后添加\\)和表格主体,每次一行。行的构建方式类似,使用内部循环。

在此处输入图片描述

相关内容