我正在尝试使用宏以更清晰的方式重新格式化内容。特别是,我希望转换如下字符串
foo; bar; baz;
进入
foo;
bar;
baz;
这是我目前拥有的宏及其在文档中的使用,工作正常:
\documentclass{article}
\usepackage{xstring}
\newcommand{\splitStatementsAndTextttize}[1]{%
\StrCut{#1}{; }\leftPart\rightPart%
\ifx\rightPart\empty
\leftPart\\%
\else
\leftPart;\\ \splitStatementsAndTextttize{\rightPart}%
\fi
}%
\begin{document}
\noindent \splitStatementsAndTextttize{foo; bar; baz;}
\end{document}
给出以下内容,并带有预期的排版:
foo;
bar;
baz;
现在,这个确切的内容实际上应该位于表格的单个单元格中。以下表格中某些单元格包含多行,这可以通过将内容放入表格来实现。
更新后的示例如下(相同的宏,不同的用途):
\documentclass{article}
\usepackage{xstring}
\newcommand{\splitStatementsAndTextttize}[1]{%
\StrCut{#1}{; }\leftPart\rightPart%
\ifx\rightPart\empty
\leftPart\\%
\else
\leftPart;\\ \splitStatementsAndTextttize{\rightPart}%
\fi
}%
\begin{document}
\begin{tabular}[x]{@{}l@{}}
\splitStatementsAndTextttize{foo; bar; baz;}
\end{tabular}
\end{document}
由于某些我无法理解的原因而失败了......
! Undefined control sequence.
<argument> \rightPart
l.15 ...plitStatementsAndTextttize{foo; bar; baz;}
答案1
问题在于表格单元格组成一个组,因此两个单元格之间的任何本地分配都会丢失。例如:
\def\cmd{?}
\begin{tabular}{cc}
\def\cmd{foo} \cmd & \cmd \\
\end{tabular}
将导致
因为当你切换到第二列时,分配就被恢复了。
您的示例中也发生了同样的情况:在第一行中分配了\leftPart
和\rightPart
,然后您执行了\leftPart \\ something with \rightPart
,但是当您尝试使用时\rightPart
,分配已被还原(因为您结束了表行)并且\rightPart
不再存在。
您有办法摆脱这种情况:首先是在表格行结束之前使用一些\expandafter
来扩展:\rightPart
\newcommand{\splitStatementsAndTextttize}[1]{%
\StrCut{#1}{; }\leftPart\rightPart%
\ifx\rightPart\empty
\leftPart\\%
\else
\leftPart;%
\expandafter\\%
\expandafter\splitStatementsAndTextttize
\expandafter{\rightPart}%
\fi
}%
第二种是根本不使用赋值(下面的代码使用分隔宏来抓取分隔的内容;
并逐个排版;这不使用xstring
):
\newcommand{\splitStatementsAndTextttize}[1]{%
\splitthingyaux#1;\splitthingyaux;}
\def\splitthingyaux#1;{%
\if\relax\detokenize{#1}\relax\else % if non-empty
\ifx\splitthingyaux#1\else % if not reached the end
\texttt{\ignorespaces#1;}\\% use item
\expandafter\expandafter
\expandafter\splitthingyaux
\fi
\fi}
还要注意是\begin{tabular}[x]
错误的(它的行为与完全相同\begin{tabular}[c]
,但它只是一个实现细节)。
完整代码:
\documentclass{article}
\usepackage{xstring}
\newcommand{\splitStatementsAndTextttize}[1]{%
\splitthingyaux#1;\splitthingyaux;}
\def\splitthingyaux#1;{%
\if\relax\detokenize{#1}\relax\else % if non-empty
\ifx\splitthingyaux#1\else % if not reached the end
\texttt{\ignorespaces#1;}\\% use item
\expandafter\expandafter
\expandafter\splitthingyaux
\fi
\fi}
% \newcommand{\splitStatementsAndTextttize}[1]{%
% \StrCut{#1}{; }\leftPart\rightPart%
% \ifx\rightPart\empty
% \leftPart\\%
% \else
% \leftPart;%
% \expandafter\\%
% \expandafter\splitStatementsAndTextttize
% \expandafter{\rightPart}%
% \fi
% }%
\begin{document}
\begin{tabular}[c]{@{}l@{}}
\splitStatementsAndTextttize{foo; bar; baz;}
\end{tabular}
\end{document}
答案2
答案3
这是 的工作expl3
。该设施将一次性\seq_map_function:NN
交付整个令牌列表,因此只有在构建了整个令牌列表后,才会“看到” 。foo \\ bar \\ baz \\
\\
您的代码的问题在于,您设置的循环从一个单元格开始tabular
,而在另一个单元格结束,这是不可能的。
\documentclass{article}
\usepackage{xstring}
\ExplSyntaxOn
\NewDocumentCommand{\splitStatementsAndTextttize}{m}
{
% split the input at semicolons
\seq_set_split:Nnn \l_tmpa_seq { ; } { #1 }
% remove the last item
\seq_pop_right:NN \l_tmpa_seq \l_tmpa_tl
% if the last item is not empty, reinsert it back
\tl_if_empty:NF \l_tmpa_tl { \seq_put_right:NV \l_tmpa_seq \l_tmpa_tl }
% map the sequence adding \\ after each item
\seq_map_function:NN \l_tmpa_seq \pamplemousse_add_endline:n
}
\cs_new_protected:Nn \pamplemousse_add_endline:n
{
#1 \\
}
\ExplSyntaxOff
\begin{document}
\begin{tabular}{@{}l@{}}
\hline
\splitStatementsAndTextttize{foo; bar; baz;}
\hline
\end{tabular}
\qquad
\begin{tabular}{@{}l@{}}
\hline
\splitStatementsAndTextttize{foo; bar; baz}
\hline
\end{tabular}
\end{document}
我添加\hline
只是为了表明无论是否有尾随分号,输出都是相同的。