我希望定义这样一个命令(比如说\test
)来将操作(比如说\action
)应用于以 分隔的文本\\
,例如\test{A\\B\\C}
将变成
\action{A}\\\action{B}\\\action{C}
这类似于这个问题,但我无法调整那里的答案来实现我在这里想要的。我该如何定义这样的宏?
答案1
\DeclareListParser
frometoolbox
就是为此而制作的,它允许您使用自定义列表分隔符定义列表解析器。(编辑:修复了一个缺点,感谢 cgnieder!)
\documentclass{article}
\usepackage{etoolbox}
\DeclareListParser{\mydocsvlist}{\\}
\newif\ifFirstItem
\newcommand{\action}[1]{\textbf{#1}}
\newcommand{\test}[1]{\begingroup
\FirstItemtrue
\renewcommand*{\do}[1]{\ifFirstItem\FirstItemfalse\else\\\fi\action{##1}}%
\mydocsvlist{#1}%
\endgroup}
\parindent0pt
\begin{document}
\test{A\\B\\C}
\renewcommand{\action}[1]{\emph{#1}!}%
\test{A\\B\\C}
\end{document}
答案2
有一种基于 TeX 基元的经典方法(也可能是最简单的方法):
\def\test#1{\testA#1\\\end\\}
\def\testA#1\\{\ifx\end#1\empty\else\action{#1}\expandafter\testA\fi}
\def\action#1{parameter is: #1\par}
\test{A\\B\\C}
例如,如果我们需要在动作之间插入一些内容\actionbetween
,那么宏会稍微复杂一些,但它也是完全可扩展的:
\def\test#1{\testA#1\\\end\\\\}
\def\testA#1\\#2\\{\ifx\end#1\empty
\else\action{#1}\ifx\end#2\empty \else \actionbetween \fi
\afterfi{\testA#2\\}\fi}
\def\afterfi#1#2\fi{\fi#1}
\def\action#1{parameter is #1\par}
\def\actionbetween{\string\\}
\test{A\\B\\C}
答案3
\documentclass{arlticle}
\usepackage{listofitems}
\newcommand\action[1]{%
\setsepchar{\\}%
\readlist\myparse{#1}%
\foreachitem\z\in\myparse[]{%
\expandafter\theaction\expandafter{\z}\myparsesep[\zcnt]%
}%
}
\newcommand\theaction{\textit}
\begin{document}
\action{A\\B\\C plus more}
\renewcommand\theaction{\textsc}
\action{A\\B\\C plus more}
\end{document}
为了使其更加通用,您还可以将其设置为指定分隔符。请注意,在第二个示例中,分隔符标记不受小写字母的影响行动。
\documentclass{arlticle}
\usepackage{listofitems}
\newcommand\action[1]{%
\readlist\myparse{#1}%
\foreachitem\z\in\myparse[]{%
\expandafter\theaction\expandafter{\z}\myparsesep[\zcnt]%
}%
}
\setsepchar{\\}
\newcommand\theaction{\textit}
\begin{document}
\action{A\\B\\C plus more}
\renewcommand\theaction{\textsc}
\setsepchar{(Hi Mom)\\}
\action{A (Hi Mom)\\B (Hi Mom)\\C plus more}
\end{document}
答案4
这是一个基于的相当通用的方法来满足您的需求expl3
。
输入在指定的分隔符处拆分(并修剪项目周围的空格);每个项目都按照模板指定的方式进行“装饰”,其中当前项目用 表示#1
;最后,“装饰后的项目”以它们之间的指定分隔符(任何有效代码)输出。
##1
请注意,如果\actonlist
在另一个命令的定义中使用,则模板参数应该具有。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\actonlist}{ m m +m m}
{% #1 = input separator
% #2 = template
% #3 = output separator
% #4 = list
\jinwen_actonlist:nnnn { #1 } { #2 } { #3 } { #4 }
}
\seq_new:N \l__jinwen_actonlist_in_seq
\seq_new:N \l__jinwen_actonlist_out_seq
\cs_new_protected:Nn \jinwen_actonlist:nnnn
{
\seq_set_split:Nnn \l__jinwen_actonlist_in_seq { #1 } { #4 }
\seq_set_map:NNn \l__jinwen_actonlist_out_seq \l__jinwen_actonlist_in_seq { #2 }
\seq_use:Nn \l__jinwen_actonlist_out_seq { #3 }
}
\ExplSyntaxOff
\begin{document}
\actonlist{\\}{\emph{#1}}{ (here a par)\par}{A\\B\\C}
\newcommand{\test}[1]{%
\actonlist
{\\}
{\emph{##1}}
{ (here a par)\par}
{#1}%
}
\test{A\\B\\C}
\newcommand{\testcomma}[1]{%
\actonlist
{,}
{\textbf{##1}}
{ (here a par)\par}
{#1}%
}
\testcomma{A, B, C}
\end{document}
从“here a par”可以看出,输出分隔符仅用于项之间。如果您还需要在末尾使用它,只需在 的定义中添加它\test
,例如
\newcommand{\test}[1]{%
\actonlist
{\\}
{\emph{##1}}
{ (here a par)\par}
{#1} (here a par)\par
}