我想要一个宏,我们称之为\csword
,它读取输入中的下一个单词(即字母序列a-zA-Z
),然后将该单词作为宏执行。例如
\csword command
\csword command[and]{arguments}
应该扩展为类似
\command
\command[and]{arguments}
接下来如果\csword
跟着除字母之外的任何字符,则应该引发错误。
以防我太过专注,试图用错误的方式解决问题,以下是我所看到的大局实际上想要做什么。我想定义一个宏,它接收多个选项作为逗号分隔的列表。但是,这些选项可能进一步接收一些参数,甚至是可选参数。换句话说,我试图把
\myfancycommand{optionA, optionB[with]{args}, optionC{fun}, optionA}
大致如下
\optionA\optionB[with]{args}\optionC{fun}\optionA
顺便说一句,这很重要,我应该能够重复“选项”及其执行顺序。
答案1
假设@是一个字母:
\def\csword{\def\csword@{}\@csword}
\def\@csword{\futurelet\next\@@csword}
\def\@@csword{\ifcat a\noexpand\next
\expandafter\@@@csword
\else\expandafter\expandafter\csname\csword@\endcsname\fi}
\def\@@@csword#1{\edef\csword@{\csword@#1}\@csword}
编辑:从第 3 行删除了\expandafter
。它是不必要的,并且会导致宏在以下情况下失败\csword foo\bar
。
答案2
我将使用其中一个 keyval 包 (keyval、xkeyval、pgfkeys...) 并定义键 optionA 等,以便您可以像这样使用它们:
\myfancycommand{optionA, optionB=[with]{args}, optionC={fun}}
答案3
万一您希望这篇文章可扩展,这里有另一个 expl3 版本。虽然这个比 Harald 的长,但我认为它的可读性更强。再想想:不,我想我只是这么想,因为我刚刚写了它:)
稍有缺点:像 这样的命令f{o}o
会像 一样执行foo
。这也意味着您无法拥有像 这样的命令foo{A}
,很遗憾。但foo{abc}
没关系。此外,空格没有任何意义:foo foo
会被处理为\foofoo
。
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new:Npn \csword #1 {
\cs:w \csword_aux:n #1
}
\cs_new:Nn \csword_aux:n {
\tl_if_empty:nTF {#1}
{ \cs_end: } % e.g., '{}' in 'foo{}': end scanning
{
\tl_if_single:nTF {#1}
{
% e.g., 'o' in 'foo' or '{A}' in 'foo{A}' or '[' in 'foo[a]':
\token_if_letter:NTF #1
{ #1 \csword_aux:n } % e.g., 'o' in 'foo' : keep scanning
{ \cs_end: #1 } % e.g., '[' in 'foo[a]' : end scanning
}
{ \cs_end: {#1} } % e.g., '{abc}' in 'foo{abc}': end scanning
}
}
\ExplSyntaxOff
\begin{document}
\newcommand\foo[1][opt]{[foo: #1]}
\newcommand\baz[2][opt]{[baz: #1/#2]}
\typeout{
\csword foo
\csword f{o}o
\csword foo{A}
\csword foo{ABC}
\csword foo[1]
\csword baz{2}
\csword baz{22}
\csword baz[333]{222}
}
\end{document}
我刚刚将其与 Harald 的解决方案进行了基准测试,结果显示它慢了五倍。所以它实际上只具有学术用途:)
答案4
ConTeXt 有一个宏,\dowithwargument
用于处理单词(w 代表单词)参数和
\dowithpargument
par(p 代表 par)参数。但是,它将单词视为由空格分隔的任何内容。因此,如果您愿意将参数键入为
\csword 选项A \csword optionB [and]{argument} % 注意 optionB 后面的空格
那么你可以定义\csword
为
\def\csword{\dowithwargument\getvalue}
编辑:另一个选择是捕获空格分隔的短语然后使用 LuaTeX在前面\dowithwargument
添加一个。所以\
\def\csword{\dowithwargument\docsword} \def\docsword#1{\ctxlua{tex.sprint("\\#1")}}