解析行(`\\`)和制表符(`&`)

解析行(`\\`)和制表符(`&`)

我有一个用于解析输入数据的用途tabular,但它不是tabular环境的一部分,而是宏的参数。因此我开发了两个宏,\readTABrow一个将&分离的列表读入不同的标记,另一个将分离的列表\readMANYrows读入许多标记。\\

当我将原本会出现在tabular“行”或“表”中的参数传递给这两个宏时,它们的行为都符合预期。问题出现在我从 中获取输出时\readMANYrows,这会为我提供每行一个标记,每个标记都填充了&- 分隔的数据,我将这个标记传递给 ,\readTABrow以便进一步将表格行解析为单个单元格数据。

我怀疑这些&字符的“性质”在被解析时会发生变化readMANYrows,当它们到达时,它们不再看起来像制表符分隔符\readTABrow

我的问题是如何&在 期间保留字符的制表符“性质” \readMANYrows,以便我可以将包含它们的令牌直接传递给\readTABrow而不会出现问题。

这是我的 MWE:

\documentclass{article}
\usepackage{ifthen}

\makeatletter

% FOR PROCESSING A &-SEPARATED ROW 
\newcounter{TABcellindex@}

\newcommand\readTABrow[2]{%
  \def\doneTABread{F}%
  \def\postTAB{#2}%
  \setcounter{TABcellindex@}{0}%
  \whiledo{\equal{\doneTABread}{F}}{%
    \stepcounter{TABcellindex@}%
    \expandafter\processTAB\postTAB&\\%
    \ifthenelse{\equal{\preTAB}{}}{%
      \addtocounter{TABcellindex@}{-1}%
      \def\doneTABread{T}%
    }{%
      \expandafter\protected@edef\csname #1X\roman{TABcellindex@}\endcsname{%
        \preTAB}%
    }%
  }%
% \#1TABcells GIVES HOW MANY TAB COLUMNS WERE PROCESSED
  \expandafter\xdef\csname #1TABcells\endcsname{\arabic{TABcellindex@}}%
}

\def\processTAB#1&#2\\{%
  \protected@edef\preTAB{#1}%
  \protected@edef\postTAB{#2}%
}

% FOR PROCESSING A \\-SEPARATED GROUP OF ROWS
\newcounter{ROWcellindex@}

\newcommand\readMANYrows[2]{%
  \def\doneROWread{F}%
  \def\postROW{#2\\}%
  \setcounter{ROWcellindex@}{0}%
  \whiledo{\equal{\doneROWread}{F}}{%
    \stepcounter{ROWcellindex@}%
    \expandafter\processROW\postROW||%
    \ifthenelse{\equal{\postROW}{}}{%
      \def\doneROWread{T}%
    }{}%
    \expandafter\protected@edef\csname #1X\roman{ROWcellindex@}\endcsname{%
      \preROW}%
  }%
% \#1ROWs GIVES HOW MANY ROWS WERE PROCESSED
  \expandafter\xdef\csname #1ROWs\endcsname{\arabic{ROWcellindex@}}%
}

\def\processROW#1\\#2||{%
  \protected@edef\preROW{#1}%
  \protected@edef\postROW{#2}%
}

\makeatother

\begin{document}
\verb|\readTABrow| Input: \verb|{a&b&c&d}|
\readTABrow{myrow}{a&b&c&d}\par
.\myrowXi.\par
.\myrowXii.\par
.\myrowXiii.\par
.\myrowXiv.\par
COLUMNS: \myrowTABcells\par
---

\verb|\readMANYrows| Input: \verb|{a&b&c&d\\b\\\\ c}|
\readMANYrows{mydata}{a&b&c&d\\b\\\\ c}\par
.\detokenize\expandafter{\mydataXi}.(detokenized)\par
.\mydataXii.\par
.\mydataXiii.\par
.\mydataXiv.\par
ROWS: \mydataROWs\par
---

\verb|\readTABrow| Input: \verb|\mydataXi|
\readTABrow{mydataXi}{\mydataXi}\par
.\detokenize\expandafter{\mydataXiXi}.(detokenized)\par
COLUMNS:\mydataXiTABcells\par

\end{document}

下面给出的输出显示了\readTABrow和的个别情况\readMANYrows,它们都按我的预期运行,而最后一个例子表明\readTABrow,当传递由生成的令牌时\readMANYrows,会错误地将该令牌确定为&免费的,由单个单元组成,而不是由 4 个单元组成

在此处输入图片描述

请注意, 的使用\detokenize仅作为调试辅助手段,用于显示包含字符的各种宏的内容&。 没有\detokenized 数据传递给\readTABrow

相关的补充说明一下,在解析&\\标记时,是否传统上会忽略它们后面的空格?正如您从我的 MWE 中看到的那样,我不会忽略它们。

更新:

David Carlisle 解决了这个问题,尽管他仍然不太清楚我想要什么。所以,让我展示一下。如果 MWE 的最后几行被替换为

\verb|\readTABrow| Input: \verb|\mydataXi|
\def\foo{\readTABrow{mydataXi}}
\expandafter\foo\expandafter{\mydataXi}\par
.\mydataXiXi.\par
.\mydataXiXii.\par
.\mydataXiXiii.\par
.\mydataXiXiv.\par
COLUMNS:\mydataXiTABcells\par

最终输出变成

在此处输入图片描述

因此,在 David 的帮助下,我可以使用我的两个例程来获取类似表格的参数,例如

{a&b&c\\d&e&f\\g&h&i}

并存储表组件,就像我输入了数组元素一样:

\edef\mydataXiXi{a}
\edef\mydataXiXii{b}
\edef\mydataXiXiii{c}
\edef\mydataXiiXi{d}
\edef\mydataXiiXii{e}
\edef\mydataXiiXiii{f}
\edef\mydataXiiiXi{g}
\edef\mydataXiiiXii{h}
\edef\mydataXiiiXiii{i}

可以通过以下方式访问\csname mydataX\roman{row}X\roman{col}\endcsname

当与参数相关的输出必须拆分(跨页面水平)或拼接(与其他数据合并),或者稍后需要调用单个单元格时,这将很有用。

答案1

我仍然不清楚您需要什么输出,但在最后一次调用中,您没有传递一个&单独的列表,而是传递了一个扩展到这样一个列表的宏,因此您需要先扩展它。

\def\foo{\readTABrow{mydataXi}}
\expandafter\foo\expandafter{\mydataXi}\par
.\detokenize\expandafter{\mydataXiXi}.(detokenized)\par
COLUMNS:\mydataXiTABcells\par

生成 COLUMNS:4 而不是 COLUMNS:1

至于相关问题,如果您试图模拟正常的 TeX\halign行为,解析器不会删除空格,因此会生成空格标记,但 LaTeX 始终避免排版由此产生的任何空白,例如每个单元前导码以 开头\ignorespaces并以 结尾\unskip(如果处于 hmode)。

答案2

我不喜欢重新发明轮子;使用 LaTeX3 宏很容易。请注意,如果将参数作为控制序列扩展为所需的标记列表,则 *-variant 用于扩展参数。如果您可以完全控制输入中可能出现的标记,即如果它们只是不可扩展的标记(但当然必须小心使用前导\\),则可以省去它。

有一些代码重复,因此宏可以简化。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\readTABrow}{ s m m }
 {
  \IfBooleanTF{#1}
   { \segle_read_tab_row:no { #2 } { #3 } }
   { \segle_read_tab_row:nn { #2 } { #3 } }
 }
\NewDocumentCommand{\readMANYrows}{ s m m }
 {
  \IfBooleanTF{#1}
   { \segle_read_many_rows:no { #2 } { #3 } }
   { \segle_read_many_rows:nn { #2 } { #3 } }
 }

\seq_new:N \l_segle_row_seq
\seq_new:N \l_segle_manyrows_seq
\int_new:N \l_segle_row_int
\int_new:N \l_segle_manyrows_int
\cs_new_protected:Npn \segle_read_tab_row:nn #1 #2
 {
  \seq_set_split:Nnn \l_segle_row_seq { & } { #2 }
  \int_zero:N \l_segle_row_int
  \seq_map_inline:Nn \l_segle_row_seq
   {
    \int_incr:N \l_segle_row_int
    \cs_set:cpn { #1 X \int_to_roman:n { \l_segle_row_int } } { ##1 }
   }
  \cs_set:cpx { #1 TABcells } { \int_to_arabic:n { \l_segle_row_int } }
 }
\cs_generate_variant:Nn \segle_read_tab_row:nn { no }

\cs_new_protected:Npn \segle_read_many_rows:nn #1 #2
 {
  \seq_set_split:Nnn \l_segle_manyrows_seq { \\ } { #2 }
  \int_zero:N \l_segle_manyrows_int
  \seq_map_inline:Nn \l_segle_manyrows_seq
   {
    \int_incr:N \l_segle_manyrows_int
    \cs_set:cpn { #1 X \int_to_roman:n { \l_segle_manyrows_int } } { ##1 }
   }
  \cs_set:cpx { #1 ROWs } { \int_to_arabic:n { \l_segle_manyrows_int } }
 }
\cs_generate_variant:Nn \segle_read_many_rows:nn { no }

\ExplSyntaxOff

\begin{document}
\verb|\readTABrow| Input: \verb|{a&b&c&d}|
\readTABrow{myrow}{a&b&c&d}\par
.\myrowXi.\par
.\myrowXii.\par
.\myrowXiii.\par
.\myrowXiv.\par
COLUMNS: \myrowTABcells\par

\verb|\readMANYrows| Input: \verb|{a&b&c&d\\b\\\\ c}|
\readMANYrows{mydata}{a&b&c&d\\b\\\\ c}\par
.\detokenize\expandafter{\mydataXi}.\par
.\mydataXii.\par
.\mydataXiii.\par
.\mydataXiv.\par
ROWS: \mydataROWs\par

---

\verb|\readTABrow| Input: \verb|\mydataXi|
\readTABrow*{mydataXi}{\mydataXi}\par
.\detokenize\expandafter{\mydataXiXi}.(detokenized)\par
COLUMNS:\mydataXiTABcells\par
\end{document}

在此处输入图片描述

相关内容