请考虑以下 MWE,对于“字符扫描”命令“ \looper
”,它利用\@tfor
:
\documentclass{minimal}
\usepackage{trace}
\makeatletter
\newcommand\looper[1]{%
% \def\looper#1{%
\typeout{#1}%
\@tfor\next:=#1 \do{\typeout{\next}%
\next%
}
}
\makeatother
\begin{document}
\looper{TEST1}
%% terminal typeout:
% TEST1
% T
% E
% S
% T
% 1
%\typeout{\looper{Test2}}
%% terminal typeout:
% ! Undefined control sequence.
% \next ->\@nil
\edef\tmptest{TEST3}
\looper{\tmptest}
%% terminal typeout:
% TEST3
% TEST3
% \traceon
\edef\outtest{\looper{\tmptest}}
%% terminal typeout:
% ! Undefined control sequence.
% \next ->\@nil
\end{document}
这里的\looper{TEST1}
行为正如我想要的那样,但我还想以某种方式使用\looper{\tmptest}
(其中\edef\tmptest{TEST3}
)并获取(在终端中):
\looper{\tmptest}
%% terminal typeout:
% TEST3
% T
% E
% S
% T
% 3
但是,函数实际上不必自行扩展参数,只要我可以在调用本身中执行某些操作即可,例如\looper{\detokenize{\tmptest}}
(否则我不能在这里使用它,因为它不会“解压”字符)
此外,该函数会“返回”\next
每个扫描到的字符,因此我希望能够编写类似
\edef\outtest{\looper{\tmptest}}
...并再次获得“TEST3”的内容- 除了这里,它们将是路由\outtest
连接的结果(\next
\looper
因此,我可以改为返回-\next
,\next
并使用如下函数获取“-TEST-3”)。
是否已经内置了类似的东西 - 或者有人可以指出包含类似功能的资源?
编辑:请注意,可能这个没有扩展,因为\@tfor
使用不可扩展的(?)命令(\@nil
) - 如果我激活,我会得到这个\traceon
:
% with \traceon:
{into \tracingonline=1}
{\edef}
\looper #1->\typeout {#1}\@tfor \next :=#1 \do {\typeout {\next }\next }
#1<-\tmptest
\typeout #1->\begingroup \set@display@protect \immediate \write \@unused {#1}\e
ndgroup
#1<-\tmptest
\set@display@protect ->\let \protect \string
{\string}
\tmptest ->TEST3
\@tfor #1:=->\@tf@r #1
#1<-\next
\@tf@r #1#2\do #3->\def \@fortmp {#2}\ifx \@fortmp \space \else \@tforloop #2\@
nil \@nil \@@ #1{#3}\fi
#1<-\next
#2<- \tmptest
#3<-\typeout {\next }\next
\@fortmp -> \tmptest
\tmptest ->TEST3
\tmptest ->TEST3
{\ifx}
{false}
\@tforloop #1#2\@@ #3#4->\def #3{#1}\ifx #3\@nnil \expandafter \@fornoop \else
#4\relax \expandafter \@tforloop \fi #2\@@ #3{#4}
#1<-\tmptest
#2<- \@nil \@nil
#3<-\next
#4<-\typeout {\next }\next
\next ->\@nil
{undefined}
! Undefined control sequence.
\next ->\@nil
答案1
正如评论中所述,您无法进行可扩展的分配,但这里有一个可扩展循环的可能定义,它只围绕[]
每个标记:
\def\expandloop#1{\xloop#1\relax}
\def\xloop#1{%
\ifx\relax#1\else[#1]\expandafter\xloop\fi}
\edef\zzzz{\expandloop{TEST1}}
\show\zzzz
\bye
运行结果如下:
$ tex loop
This is TeX, Version 3.1415926 (TeX Live 2011/Cygwin)
(./loop.tex
> \zzzz=macro:
->[T][E][S][T][1].
l.8 \show\zzzz
答案2
在 LaTeX3 中,我们有一个名为 的循环\tl_map_function:nN
,它似乎可以满足您的要求。当然,它可以用原语重新编码,为了方便参考,我在这里这样做了:
\documentclass{article}
\usepackage{pdftexcmds}
\makeatletter
\long\def\expandableloop#1#2{%
\expandableloop@aux#1#2\q@recursion@tail
\break@point
}
\long\def\expandableloop@aux#1#2{%
\break@if@quark@tail{#2}%
#1{#2}%
\expandableloop@aux#1%
}
\long\def\break@if@quark@tail#1{%
\ifnum\pdf@strcmp{\noexpand\q@recursion@tail}{\unexpanded{#1}}=\z@
\expandafter\break@if@quark@tail@aux
\fi
}
\long\def\break@if@quark@tail@aux#1\break@point{}
\makeatletter
\newcommand\looper[1]{%
\expandableloop\detokenize{#1}
}
\makeatother
\begin{document}
\def\tmptest{TEST3}
\edef\outtest{\expandafter\looper\expandafter{\tmptest}}
\show\outtest
\end{document}
请注意,这依赖于\pdfstctmp
或等效功能:我已加载包pdftexcmds
来整理此处的引擎可变性。还请注意,这不会“意外地”扩展输入,因此我不得不故意使用 来这样做\expandafter
。