如何/可能改变此实现\xSplit
以便分隔符是在定义时(\edef
以某种方式?)或在实际使用命令时填写的变量?
%based on the following code
%TeX by Topic unknown number of arguments p105
%\White(K1a,Q2b,3c,P4d)%
\def\endpiece{xxx}% a sentinel that ends the lists of inputs
\def\dosomethingwithsplitofpiece#1{*#1}
举个简单的例子:在它前面放一颗星星
\def\sep{,}
\xSplit
我想在像的定义中使用它,其中各部分之间的分隔符\def\xSplit#1\sep{...}
是\sep
:以下示例中的逗号。我当然可以使用函数\xSplitComma
来拆分逗号和
\xSplitSemicolon
...,其中这些分隔符是硬连线的,但我希望它是一个变量,这样我只需定义
\xSplit
一次,其中\sep
和\dosomethingwithsplitofpiece
是按照我的意愿定义的额外的问题:是否可以\sep
在内部重新定义\dosomethingwithsplitpiece
,以便在例如\xSplit
上拆分,;
而不是,
例如在找到一定数量的 之后或递归地拆分,其中首先用逗号分隔,然后这些块因此用分号分隔,依此类推。
\def\xSplit#1,{\def\temp{#1}% replace , by \sep
\ifx\temp\endpiece% no more to process
\else%
\dosomethingwithsplitofpiece{#1}%
\expandafter\xSplit%
\fi%
}%
\def\Split(#1){#1 transforms into \xSplit#1,xxx,% >-- how this comma as a variable
% that can be changed if necessary??
}%
这是一个以逗号分隔的数字列表,作为示例,然后在每次块分割前放置一个星号
\Split(4,5,6,7,9,10,11)
% \Split(4,5,6;7,9,10;11){1}
\bye
答案1
您必须每次重新定义拆分宏,因为您不知道调用时分隔符是什么:
\def\Split(#1){%
\makexSplit
\expandafter\xSplit\expandafter{\sep}{#1}%
}
\def\xSplit#1#2{\xxSplit#2#1\endpiece#1}
\def\makexSplit{%
\begingroup\edef\x{\endgroup\def\noexpand\xxSplit####1\sep}%
\x{%
\def\temp{##1}%
\ifx\temp\endpiece
\else
\dosomethingwithsplitofpiece{##1}%
\expandafter\xxSplit
\fi
}%
}
\def\endpiece{\endpiece} % don't use \endpiece in the wild!
\def\dosomethingwithsplitofpiece#1{*#1}
\def\sep{,}
\Split(4,5,6,7,9,10,11)
\def\sep{;}
\Split(4;5;6;7;9;10;11)
\bye
唯一不能出现在列表中的标记是\endpiece
。请注意,在文档中除了在此上下文(或与终止符类似的上下文)之外使用它会导致无限循环。
线条
\begingroup\edef\x{\endgroup\def\noexpand\xxSplit####1\sep}%
\x{%
可能会被替换为
\expandafter\def\expandafter\xxSplit\expandafter##\expandafter1\sep{%
如果\sep
预计包含不存在的标记\edef
。
使用更高级别的解决方案expl3
(但这需要 e-TeX):
\input expl3-generic
\ExplSyntaxOn
\seq_new:N \l_lampter_split_arg_seq
\cs_new_protected:Npn \Split ( #1 )
{
\seq_set_split:NVn \l_lampter_split_arg_seq \sep { #1 }
\seq_map_inline:Nn \l_lampter_split_arg_seq
{
\dosomethingwithsplitofpiece{##1}
}
}
\cs_generate_variant:Nn \seq_set_split:Nnn { NV }
\ExplSyntaxOff
\def\dosomethingwithsplitofpiece#1{*#1}
\def\sep{,}
\Split(4,5,6,7,9,10,11)
\def\sep{;}
\Split(4;5;6;7;9;10;11)
\bye
宏\Split
将使用当前的值来\sep
分割参数。然后\seq_map_inline:Nn
处理循环。
答案2
您可以定义\declaresplitsep
宏,并\split
使用所需的分隔符重新定义宏:
\def\dosomethingwithsplitofpiece#1{*#1}
\def\declaresplitsep#1{%
\def\split(##1){\splitA##1#1#1}%
\def\splitA##1#1{\ifx#1##1#1\else\dosomethingwithsplitofpiece{##1}\expandafter\splitA\fi}%
}
\declaresplitsep,
\split(4,5,6,7,9,10,11)
\declaresplitsep;
\split(4;5;6;7;9;10;11)
\end
这似乎有点神秘。所以,我展示了我如何编写这个宏。首先,我\split
用具体的分隔符(逗号)定义了:
\def\split(#1){\splitA#1,,}%
\def\splitA#1,{\ifx,#1,\else \dosomethingwithsplitofpiece{#1}\expandafter\splitA \fi}
其次,我将这段代码打包到并将\def\declaresplitsep#1{...}
所有标记加倍#
,最后用 替换逗号#1
。