我想从宏中积累一些文本并将其放置在多部分 Ti 中钾Z 节点。工作正常,直到文本中出现宏,此时 TeX 失败。如前所述,可以\noexpand
在文本中添加宏,但由于可能有很多文本包含不太理想的宏。我查看了评论中的一些指针\unexpanded 因未定义的 LaTeX 符号而失败?,但目前还没有找到解决方法。
\documentclass{article}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart}
\NewDocumentCommand{\foo}{m}{%
\foreach \m [count=\sn from 1] in {#1}{%
\xappto{\mtext}{\noexpand\nodepart{\numword{\sn}} \m}
}%
}
\def\numword#1{%
\ifcase#1 \or one\or two\or three\or four\or five\or six\or seven\or eight\or nine\or ten\or eleven\or twelve\or thirteen\or fourteen \or fifteen\or sixteen\or seventeen\or eightteen\or nineteen\or twenty\fi
}
%% |=====8><-----| %%
\parindent0pt
\begin{document}
\begin{tikzpicture}
\node[draw,rectangle split,rectangle split parts=20,rectangle split ignore empty parts]
{\foo{1,2,3,4}\mtext}; %% <<-- no error
%{\foo{\emph{1},2,3,4}\mtext}; %% <<-- error
%{\foo{\noexpand\emph{1},2,3,4}\mtext}; <<-- no error
\end{tikzpicture}
\end{document}
答案1
列表中的每个项目都存储在 中\m
,因此您需要扩展\m
一次,但不要超过一次,以避免\emph
爆炸等情况。一次点击\expandafter
将扩展某物一次,并\unexpanded
阻止该物扩展,因此如果将两者结合起来,您将获得:
\unexpanded\expandafter{\m}
(\expandafter
跳过括号并扩展\m
)。你不需要\expandafter
before,\unexpanded
因为\unexpanded
(就像\toks<num>
、\detokenize
、\scantokens
等一样)会扩展 之前的所有标记{
。
此外,还etoolbox
提供了一个方便命名的\expandonce
宏,它的作用正是如此:
\documentclass{article}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart}
\NewDocumentCommand{\foo}{m}{%
\foreach \m [count=\sn from 1] in {#1}{%
\xappto{\mtext}{\noexpand\nodepart{\numword{\sn}} \expandonce{\m}}
}%
}
\def\numword#1{%
\ifcase#1 \or one\or two\or three\or four\or five\or six\or seven\or eight\or nine\or ten\or eleven\or twelve\or thirteen\or fourteen \or fifteen\or sixteen\or seventeen\or eightteen\or nineteen\or twenty\fi
}
%% |=====8><-----| %%
\parindent0pt
\begin{document}
\begin{tikzpicture}
\node[draw,rectangle split,rectangle split parts=20,rectangle split ignore empty parts]
{\foo{\emph{1},2,3,4}\mtext}; %% <<-- error
\end{tikzpicture}
\end{document}
答案2
强制expl3
版本:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart}
\ExplSyntaxOn
\NewDocumentCommand{\foo}{m}
{
\seq_set_from_clist:Nn \l_tmpa_seq { #1 }
\tl_clear:N \l_tmpa_tl
\seq_map_indexed_inline:Nn \l_tmpa_seq
{
\tl_put_right:Nx \l_tmpa_tl { \exp_not:N \nodepart{\numword{##1}}~\exp_not:n { ##2 } }
}
\tl_use:N \l_tmpa_tl
}
\ExplSyntaxOff
\newcommand\numword[1]{%
\ifcase#1 \or one\or two\or three\or four\or five\or six\or
seven\or eight\or nine\or ten\or eleven\or twelve\or thirteen\or
fourteen\or fifteen\or sixteen\or seventeen\or eightteen\or
nineteen\or twenty\fi
}
\begin{document}
\begin{tikzpicture}
\node[draw,rectangle split,rectangle split parts=20,rectangle split ignore empty parts]
{\foo{1,2,3,4}};
\end{tikzpicture}
\bigskip
\begin{tikzpicture}
\node[draw,rectangle split,rectangle split parts=20,rectangle split ignore empty parts]
{\foo{\emph{1},2,3,4}};
\end{tikzpicture}
\end{document}
列表被转换为序列,因此我们可以\seq_map_indexed_inline:Nn
在循环代码中使用 where 来#1
引用索引,并#2
引用项目。由于我们处于定义中,因此它们变为##1
和##2
。
这将填充一个令牌列表变量,我们只需扩展它\numword
,就可以立即交付。
一个“更清洁”的版本,无需通过使用间接来抑制扩展。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart}
\ExplSyntaxOn
\NewDocumentCommand{\foo}{m}
{
\sgmoye_foo:n { #1 }
}
\seq_new:N \l__sgmoye_foo_items_seq
\tl_new:N \l__sgmoye_foo_body_tl
\cs_new_protected:Nn \sgmoye_foo:n
{
\seq_set_from_clist:Nn \l__sgmoye_foo_items_seq { #1 }
\tl_clear:N \l__sgmoye_foo_body_tl
\seq_map_indexed_function:NN \l__sgmoye_foo_items_seq \sgmoye_foo_add:nn
\tl_use:N \l__sgmoye_foo_body_tl
}
\cs_new_protected:Nn \sgmoye_foo_add:nn
{
\__sgmoye_foo_add:en { \numword{#1} } { #2 }
}
\cs_new_protected:Nn \__sgmoye_foo_add:nn
{
\tl_put_right:Nn \l__sgmoye_foo_body_tl { \nodepart{#1} #2 }
}
\cs_generate_variant:Nn \__sgmoye_foo_add:nn { e }
\ExplSyntaxOff
\newcommand\numword[1]{%
\ifcase#1 \or one\or two\or three\or four\or five\or six\or
seven\or eight\or nine\or ten\or eleven\or twelve\or thirteen\or
fourteen\or fifteen\or sixteen\or seventeen\or eightteen\or
nineteen\or twenty\fi
}
\begin{document}
\begin{tikzpicture}
\node[draw,rectangle split,rectangle split parts=20,rectangle split ignore empty parts]
{\foo{1,2,3,4}};
\end{tikzpicture}
\bigskip
\begin{tikzpicture}
\node[draw,rectangle split,rectangle split parts=20,rectangle split ignore empty parts]
{\foo{\emph{1},2,3,4}};
\end{tikzpicture}
\end{document}