没有任何内置循环宏,我们可以仅使用递归宏来获取 abcde 吗?

没有任何内置循环宏,我们可以仅使用递归宏来获取 abcde 吗?

在没有任何内置循环宏的情况下,我们可以仅使用递归宏来获得输出a-b-c-d-e吗?

\def\aaa #1{#1-\aaa}
\aaa abcde
% expected result : a-b-c-d-e
\bye

编辑:

可能最好的调用方式\aaa应该是\aaa{abcde}终止递归的条件仍然是一个悬而未决的问题。

答案1

如果预期的参数\aaa是一串字符,那么

\catcode`@=11
\def\aaa#1{\a@a#1\@nil}
\def\a@a#1{\ifx#1\@nil\expandafter\empty\else#1-\expandafter\a@a\fi}
\catcode`@=12

\aaa{abcde}

\bye

可以。如果参数更复杂,带有括号组或宏,则更困难。

这是完全可扩展的,并且\edef\foo{\aaa{abcde}}\show\foo会输出

> \foo=macro:
->a-b-c-d-e-.

您的第一次尝试无法成功,因为没有终止条件。

-可以按如下方式添加对支撑组的支持并删除尾随部分:

\catcode`@=11
\def\q@stop{\q@stop}
\def\q@nil{\q@nil}
\long\def\@gobble#1{}
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
\def\aaa#1{\aa@#1\q@stop\q@nil}
\def\aa@#1#2{%
  \ifx\q@stop#2%
    #1\expandafter\@firstoftwo
  \else
    #1-\expandafter\@secondoftwo
  \fi
  {\@gobble}%
  {\aa@{#2}}%
}
\catcode`@=12

\aaa{abcde}

\aaa{a{bc}de}

\bye

注意\aa@有两个参数,所以我们可以吸收一个组;测试是在第二个参数上进行的,如果 ,则停止递归\q@stop。我把 的情况留作练习\aaa{}

答案2

以下示例使用空格作为终止符,并支持使用括号(包括空括号)对字母进行分组。该解决方案可扩展:

\def\aaa#1 {%
  \aaaX#1\empty\empty
}
\def\aaaX#1#2{%
  #1%
  \ifx\empty#2\longempty
    \expandafter\gobble
  \else
    -% 
    \expandafter\aaaX
  \fi
  {#2}%
}
\long\def\longempty{}
\long\def\gobble#1{}

%%% test %%%

\def\test#1{%
  \immediate\write16{[\noexpand\aaa #1 ] => [\aaa #1 ]}%
}
\test{abcde}
\test{a}  
\test{}   
\test{aaa}
\test{x{}{yy}}
\bye

结果:

[\aaa abcde ] => [a-b-c-d-e]
[\aaa a ] => [a]
[\aaa  ] => []
[\aaa aaa ] => [a-a-a]
[\aaa x{}{yy} ] => [x--yy]

答案3

@egreg 的回答有一个错误:问题作者不希望最后一个字母后面有连字符。有一个完整的可扩展解决方案可以解决这个问题:

\def\aaa #1{\ifx\end#1\end\else \aaaB #1\end\fi}
\def\aaaB #1#2\end{#1\aaaC#2\end} 
\def\aaaC #1{\ifx\end#1\empty\else -#1\expandafter\aaaC \fi}

\aaa {abcde}

\bye

编辑:我添加了一个\ifx以接受空参数。还支持使用括号(包括空括号)对字母进行分组。

相关内容