将下一个单词解析并执行为命令?

将下一个单词解析并执行为命令?

我想要一个宏,我们称之为\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 代表单词)参数和 \dowithpargumentpar(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")}}

相关内容