以下导致我出现此错误
!不完整 \iffalse;第 26 行之后的所有文本均被忽略。
那么,如何使\if
存储在宏中的表里面的工作呢\MyTable
?
\newif\ifShowRow
\ShowRowfalse
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
3 & 4 \\
\ifShowRow
5 & 6 \\
\fi
7 & 8 \\
9 & 10 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \MyTable ]{ colspec = {X S} }
One & {{{Two}}} \\
\MyTable
\end{tblr}
\end{document}
更新
采用这个答案,我无法让下面的代码工作
\newif\ifShowRow
\ShowRowfalse
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
% https://tex.stackexchange.com/a/58627/2288
\ifthenelse{\boolean{ShowRow}}{ 3 & 4 \\ 5 & 6 \\ }{ 7 & 8 \\ 9 & 10 \\}
9 & 10 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray, xifthen}
\UseTblrLibrary{siunitx}
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \MyTable ]{ colspec = {X S} }
One & {{{Two}}} \\
\MyTable
\end{tblr}
\end{document}
答案1
来自包的环境表格数组解析它们的“主体”以获取表的支架/框架。解析例程似乎“期望”构成表的支架/框架的标记原样存在于环境主体中。解析例程似乎“期望”不需要通过以任何方式执行来自这些环境“主体”的事情来获取这些标记。
扩展是 TeX 中执行事物的一种方法/概念。
为了在解析过程中获得一些扩展支持,最近发布的表格数组-packageexpand=...
提供了 -key,但这反过来意味着作为该键的值提供的标记必须是完全可扩展的。
但\ifthenelse
不是完全可扩展的。
\ifthenelse
是一个宏,它在其他东西之下产生用于触发执行临时分配/触发(重新)定义临时宏/临时宏的标记。TeX
不会在扩展阶段执行分配,而是在其“消化过程”的后期阶段执行分配。
使用 Donald E. Knuth 的类比,TeX 是一只有眼睛和消化道的野兽,扩展发生在食道中,分配在胃中进行,此时扩展已经完成。
使用来自包的环境表格数组检测表的支架/框架的大量解析工作是通过包提供的“内部”例程完成的。来自环境主体并形成这些内部例程的参数的标记不会展开以供进一步检查。它们不会以任何方式执行。除非它们作为 -key 的值出现expand=...
。在这种情况下,触发一个扩展步骤似乎是“执行”的唯一可能方式。执行任务是不可能的。
我使用了“一步扩展”这个短语,因为 TeX 的 gullet 扩展通常是一个“反刍过程”。也就是说,如果扩展一个可扩展标记会产生另一个可扩展标记,而现在它是标记流的第一个标记,那么另一个可扩展标记也会被扩展。使用 -key 似乎expand=...
不会发生反刍。你只会得到另一个可扩展标记,仅此而已。
但你可以轻松地建立“反流”:
\romannumeral
作为一种技巧,您可以触发使用扩展expand = \romannumeral
和(ab?)使用\romannumeral
扩展来触发大量的扩展工作。
-expansion的要点\romannumeral
是:
\romannumeral
收集标记,直到收集到一组形成有效 TeX 的标记为止⟨数字⟩-quantity(或看到需要引发错误消息)。可扩展令牌在收集时会扩展。
如果 TeX-⟨数字⟩-quantity 确实表示一个正整数,你会得到类别 12(其他)的明确字符标记,它们以小写罗马数字的形式表示该 TeX- 当前所表示的值⟨数字⟩-数量。
如果 TeX-⟨数字⟩-quantity 表示一个非正整数,形成 TeX-⟨数字⟩-quantity 被默默丢弃,没有任何(令人不安的错误)消息,并且 TeX 也不会返回任何标记。
后一种情况对于我们的目的来说更有趣:
你可以(滥用?)使用\romannumeral
它来触发 TeX 做大量的(宏)扩展工作(“标记替换”工作)和“在标记流中交换标记”工作/“在标记流中翻转标记”工作,只要确保在所有这些扩展和交换/翻转工作之后,标记流中的下一个标记是 TeX-⟨数字⟩-quantity 表示一个非正值的整数。
在下面的例子中,提供了 TeX-⟨数字⟩-quantity 表示一个非正整数,我使用标记\stopexpansion
,定义为\chardef\stopexpansion=`\^^00
。\stopexpansion
是一个\chardef
-token ,在收集 TeX- 的上下文中⟨数字⟩-quantity 被假定为表示非正值“0”。TeX 收集 TeX 的规则-⟨数字⟩-quantity 表示在 TeX-⟨数字⟩所讨论的 -quantity 由 -token 组成\chardef
。此外,这\stopexpansion
也是一个控制字标记,因此不受\uppercase
或 之类的影响\lowercase
。
在下面的例子中,为了触发扩展,我实际上使用了。但我将其用作与 相等的\romannumeral
标记。\startexpansion
\let
\romannumeral
除此之外,对于一般的表格,您需要确保像&
和这样的内容\\
嵌套在花括号中,直到完成最后的扩展步骤,此后只剩下那些应该真正形成表格框架/支架的标记。
否则,TeX 自身用于解析/检测表格框架/支架的机制可能会拦截扩展并将内容作为表格单元格的内容,而这些内容实际上应该通过扩展删除。
您可以通过将内容作为括号嵌套的宏参数传递来做到这一点,例如 for\@firstoftwo
或\@secondoftwo
。
(\@firstoftwo
是 LaTeX 2ε 内核的宏,它选择两个未分隔/括号嵌套参数中的第一个。
\@secondoftwo
是 LaTeX 2ε 内核的宏,它选择两个未分隔/括号嵌套参数中的第二个。)
\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
\csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
\makeatother
\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
\startexpansion
\ExpandableConditionCheckTrueFalse{ShowRow}%
{\stopexpansion 3 & 4 \\ 5 & 6 \\ }%
{\stopexpansion 7 & 8 \\ 9 & 10 \\}%
11 & 12 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
One & {{{Two}}} \\
\startexpansion\expandafter\stopexpansion\MyTable
\end{tblr}
\end{document}
如果您愿意,您可以将其放入\stopexpansion
定义文本中\ExpandableConditionCheckTrueFalse
。
\ExpandableConditionCheckTrueFalse
那么在任何情况下,在 tabularray 环境之外的语法也是
\startexpansion\ExpandableConditionCheckTrueFalse{<name of \if-switch without leading "if">}{<true code>}{<false code>}
。
即,必须始终以(或)\ExpandableConditionCheckTrueFalse
开头。\startexpansion
\romannumeral
(顺便说一句:我决定⟨不带前导“if”的 \if-switch 名称⟩而不是\if..
直接提供 -token,因为这样你就不会\if..
在代码的顶层出现不平衡的 -token。否则,你必须编写类似
\ExpandableConditionCheckTrueFalse{\ifShowRow}{<true code>}{<false code>}%
这里\ifShowRow
不平衡,当嵌入到周围的- - -表达式\fi
中时会引起麻烦,因为- - -嵌套独立于任何类型的组嵌套,即也独立于括号组嵌套。)\if..
\else
\fi
\if..
\else
\fi
\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
\csname if#1\endcsname
\expandafter\expandafter\expandafter\stopexpansion\expandafter\@firstoftwo
\else
\expandafter\expandafter\expandafter\stopexpansion\expandafter\@secondoftwo
\fi
}%
\makeatother
\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
\startexpansion
\ExpandableConditionCheckTrueFalse{ShowRow}%
{3 & 4 \\ 5 & 6 \\ }%
{7 & 8 \\ 9 & 10 \\}%
11 & 12 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
One & {{{Two}}} \\
\startexpansion\expandafter\stopexpansion\MyTable
\end{tblr}
\end{document}
\startexpansion
我不建议在另一个宏中“隐藏” 。
目前expand =...
仅适用于一个令牌。
即,使用\begin{tblr}[expand = \foo, expand = \bar ]
指令expand = \bar
将覆盖指令,并且只有在解析环境主体时才会触发expand = \foo
的扩展。\bar
当“隐藏”\startexpansion
在另一个宏中时,您需要expand=<that other macro-token wherein \startexpansion is hidden>
应用
- 让你的宏的顶层扩展不再进一步扩展,并且
- 消灭前面的
expand=\startexpansion
。即,您无法\startexpansion
再使用任何 来触发其他事物的扩展。例如,您将无法触发通过 定义的宏的扩展\CatchFileDef
。
但我可以给你一个宏,以便更好地控制扩展并避免大链\expandafter
:
%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%% -> <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
\UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
\expandafter\UD@innerExp\expandafter{\expandafter}%
\romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
\UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%
将其集成到 MWE 中的方法如下:
\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
\csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%% -> <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
\UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
\expandafter\UD@innerExp\expandafter{\expandafter}%
\romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
\UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%
\makeatother
\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
\startexpansion\Expandsteps{5}%
% 5 expansion-steps are needed:
% 1st step expands `\ExpandableConditionCheckTrueFalse`.
% 2nd step expands `\csname if<foobar>\endcsname`. This yields a token `\if<foobar>`.
% 3rd step expands the token `\if<foobar>`.
% In case condition is true this leads to removal of
% the token `\if<foobar>`.
% In case condition is false this leads to removal of
% the entire true-branch and `\else`.
% 4th step:
% In case condition is true this expands `\expandafter` before
% `\@firstoftwo` which in turn expands `\else` behind `\@firstoftwo`
% which leads to removal of the entire `\else-branch and
% the `\fi`.
% In case condition is false this expands `\expandafter` before
% `\@secondoftwo` which in turn expands `\fi` behind `\@secondoftwo`
% which leads to removal of `\fi`.
% 5th step:
% In case condition is true this expands the remaining `\@firstoftwo`.
% In case condition is false this expands the remaining `\@secondoftwo`.
\ExpandableConditionCheckTrueFalse{ShowRow}%
{3 & 4 \\ 5 & 6 \\ }%
{7 & 8 \\ 9 & 10 \\}%
11 & 12 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
One & {{{Two}}} \\
\startexpansion\expandafter\stopexpansion\MyTable
%\startexpansion\Expandsteps{1}\MyTable
\end{tblr}
\end{document}
如果您愿意,您可以将其硬编码\Expandsteps
为\ExpandableConditionCheckTrueFalse
— 如果您这样做,那么,就像将其硬编码为一样\stopexpansion
,\ExpandableConditionCheckTrueFalse
每个实例都\ExpandableConditionCheckTrueFalse
需要以 为前缀\startexpansion
。因此,当涉及到嵌套时,需要触发较少量的扩展步骤,因为每个步骤本身都会触发更多步骤,但需要更频繁地提供\startexpansion
令牌:\startexpansion
\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
\Expandsteps{4}%
% 4 expansion-steps are needed:
% 1st step expands \csname if<foobar>\endcsname. This yields a token \if<foobar>.
% 2nd step expands the token \if<foobar>.
% 3rd step expands \expandafter before \@firstoftwo/\@secondoftwo.
% 4th step expands \@firstoftwo/\@secondoftwo.
\csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%% -> <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
\UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
\expandafter\UD@innerExp\expandafter{\expandafter}%
\romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
\UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%
\makeatother
\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
\startexpansion % \startexpansion triggers expansion until finding \stopexpansion.
% So \startexpansion triggers expansion of \ExpandableConditionCheckTrueFalse
% which in turn internally uses `\Expandsteps` which in turn after the amount
% of expansion-steps needed delivers \stopexpansion.
\ExpandableConditionCheckTrueFalse{ShowRow}%
{3 & 4 \\ 5 & 6 \\ }%
{7 & 8 \\ 9 & 10 \\}%
11 & 12 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}
\newif\iffoo\footrue
\newif\ifbar\bartrue
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
\startexpansion\Expandsteps{2}% <- Just some example of controlling expansion when nesting \ExpandableConditionCheckTrueFalse:
\startexpansion\ExpandableConditionCheckTrueFalse{foo}{%
\startexpansion
\ExpandableConditionCheckTrueFalse{bar}{One footrue/bartrue & {{{Two footrue/bartrue}}}}%
{One footrue/barfalse & {{{Two footrue/barfalse}}}}%
}%
{%
\startexpansion
\ExpandableConditionCheckTrueFalse{bar}{One foofalse/bartrue & {{{Two foofalse/bartrue}}}}%
{One foofalse/barfalse & {{{Two foofalse/barfalse}}}}%
}%
\\
\startexpansion\Expandsteps{1}\MyTable
\end{tblr}
\end{document}
如果您不进行硬编码\Expandsteps
或\stopexpansion
输入,\ExpandableConditionCheckTrueFalse
则需要指定更多的扩展步骤,但您不需要\startexpansion
那么频繁:
\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
\csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%% -> <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
\UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
\expandafter\UD@innerExp\expandafter{\expandafter}%
\romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
\UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%
\makeatother
\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
\startexpansion % \startexpansion triggers expansion until finding \stopexpansion.
\ExpandableConditionCheckTrueFalse{ShowRow}%
{\stopexpansion 3 & 4 \\ 5 & 6 \\ }%
{\stopexpansion 7 & 8 \\ 9 & 10 \\}%
11 & 12 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}
\newif\iffoo\footrue
\newif\ifbar\bartrue
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
\startexpansion\Expandsteps{10}% <- Just some example of controlling expansion when nesting \ExpandableConditionCheckTrueFalse:
\ExpandableConditionCheckTrueFalse{foo}{%
\ExpandableConditionCheckTrueFalse{bar}{One footrue/bartrue & {{{Two footrue/bartrue}}}}%
{One footrue/barfalse & {{{Two footrue/barfalse}}}}%
}%
{%
\ExpandableConditionCheckTrueFalse{bar}{One foofalse/bartrue & {{{Two foofalse/bartrue}}}}%
{One foofalse/barfalse & {{{Two foofalse/barfalse}}}}%
}%
\\
\startexpansion\Expandsteps{1}\MyTable
\end{tblr}
\end{document}
如果您不想跟踪扩展步骤的数量,就不要对内容进行硬编码,而是将其\stopexpansion
作为每个最终分支的第一个标记:
\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
\csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
\makeatother
\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue
\begin{filecontents*}[overwrite]{mytable.tex}
1 & 2 \\
\startexpansion % \startexpansion triggers expansion until finding \stopexpansion.
\ExpandableConditionCheckTrueFalse{ShowRow}%
{\stopexpansion 3 & 4 \\ 5 & 6 \\ }%
{\stopexpansion 7 & 8 \\ 9 & 10 \\}%
11 & 12 \\
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}
\newif\iffoo\footrue
\newif\ifbar\bartrue
\begin{document}
\CatchFileDef{\MyTable}{mytable.tex}{}
\begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
\startexpansion
\ExpandableConditionCheckTrueFalse{foo}{%
\ExpandableConditionCheckTrueFalse{bar}{\stopexpansion One footrue/bartrue & {{{Two footrue/bartrue}}}}%
{\stopexpansion One footrue/barfalse & {{{Two footrue/barfalse}}}}%
}%
{%
\ExpandableConditionCheckTrueFalse{bar}{\stopexpansion One foofalse/bartrue & {{{Two foofalse/bartrue}}}}%
{\stopexpansion One foofalse/barfalse & {{{Two foofalse/barfalse}}}}%
}%
\\
\startexpansion\expandafter\stopexpansion\MyTable
\end{tblr}
\end{document}
答案2
实现条件表的一种方法是将表格数据的积累与表格的排版分开:
o\ResetTableTokens
清除任何先前定义的表,
o\AddTableTokens{}
根据适当的条件构建该表数据。例如
\ifShowRow
\AddTableTokens{5 & 6 \\}%
\fi
o\PrintTableTokens
在表格中打印表格数据。
有了\ShowRowfalse
,这就产生了
参考:
笔记:
booktabs
我认为这个包一定有用于表格。如果您不熟悉此包,请查看。
代码:
\documentclass{article}
\usepackage{booktabs}% Better tabbles
%% Based on:
%% https://tex.stackexchange.com/q/175568/4301
%% https://tex.stackexchange.com/q/165126/4301
%%
\newcommand*{\MyTempTableTokens}{}%
\makeatletter
\newtoks\@tabtoks
%%% assignments to \@tabtoks must be global, because they are done in \foreach
\newcommand\AddTableTokens[1]{\global\@tabtoks\expandafter{\the\@tabtoks#1}}
\newcommand\eAddTableTokens[1]{%
\protected@edef\MyTempTableTokens{#1}%
\expandafter\AddTableTokens\expandafter{\MyTempTableTokens}%
}
%%% variable should always be operated on always locally or always globally
\newcommand*\ResetTableTokens{\global\@tabtoks{}}
\newcommand*\PrintTableTokens{\the\@tabtoks}
\makeatother
\newif\ifShowRow
\ShowRowfalse
\begin{document}
% --------------------------- Build Table
\ResetTableTokens%
\AddTableTokens{1 & 2 \\}%
\AddTableTokens{3 & 4 \\}%
\ifShowRow
\AddTableTokens{5 & 6 \\}%
\fi
\AddTableTokens{7 & 8 \\}%
\AddTableTokens{9 & 10 \\}%
% --------------------------- Typeset Table
\begin{tabular}{cc}
\multicolumn{2}{c}{Heading} \\
\cmidrule{1-2}
\PrintTableTokens
\bottomrule
\end{tabular}%
\end{document}