解析纯文本和命令的混合

解析纯文本和命令的混合

我正在尝试实现一个命令,该命令可以解析某些表达式,该表达式可以是纯文本、带有其(任意数量的)参数的命令,甚至——如果我理解正确的话——不可扩展的部分。

在解析结束时,我希望逐个“item”扫描输入的“item”,其中一个 item 要么是单个字符,可能是一对 {},任何命令及其参数,要么是单个不可扩展的东西。

我的第一次尝试是使用以下方法递归扫描输入:

\NewDocumentCommand\scan{m u{\relax}}{%
    #1%
    \ifblank{#2}
        {}{,\scan#2\relax}%
}

渲染a,b,c,d\scan abcd\relax。但是,命令必须包装才能工作,如 : \scan a{\vec x}bcd\relax,它正确呈现a,x,b,c,d(其中 x 有一个向量箭头)。根据它们的定义方式,即使是零元命令也需要包装。这个要求对我来说非常烦人,所以我希望摆脱它。此外,包装{⋅⋅⋅}最终需要递归解析,因此使用它来保护命令最终是不可接受的,因为它不会再解决问题。

我的第二次尝试是在输入中使用 xstring,不幸的是它只适用于纯文本。

我的第三次尝试是去标记化/重新标记化。但我找不到如何操作\tokenize的方法,也没有找到相关文档:\tokenize{\detokenize{⋅⋅⋅}}例如,会产生不相关的错误。此外,我不确定这会带来实际的解决方案,因为这会给我带来抓取命令及其所有参数的问题,更不用说删除空格的潜在麻烦了。

最后,我回到了第一次尝试,但希望\expandafter将命令及其参数转换为独特的“实体”东西,如下所示:

\NewDocumentCommand\scan{m u{\relax}}{%
    #1%
    \ifblank{#2}
        {}{,\expandafter\scan#2\relax}%
}
\NewDocumentCommand\scanit{m}{%
    \expandafter\scan#1\relax%
}

当输入包含命令时,我无法进行编译,例如我想\(scanit {\vec abcd}\)渲染a,b,c,d(其中 a 有一个矢量箭头),但我得到了:Extra }, or forgotten $. \(\scanit {\vec abcd}\)。事实上,有些情况下它不起作用,但如果没有\expandafter——例如有一些无效值,它就会起作用。

显然,我无法控制我在这里所做的一切,因此任何解释都值得感激

答案1

目前还不清楚你想要实现什么,但该tokcycle包被设置为遍历输入流的每个标记并根据用户定义的指令。标记和支撑材料被归类为字符、组、宏或空间 (CGMS),每种都有自己的指令。

虽然可以指示它在处理输入时直接流式传输输出,但这仅适用于简单的字符输入流。如果涉及宏,则在其参数被处理之前无法执行宏。因此,典型且推荐的操作模式是处理输入并将处理后的标记收集到提供的标记列表中,称为\cytoks。对 的调用\addcytoks是将处理后的输出添加到标记列表的调用。然后,一旦到达环境的末尾,\cytoks就会呈现处理后的标记列表。

指令中的#1指的是正在处理的“当前标记”。在整个环境中,给定类型 C、G、M 或 S 的所有标记将依次通过其各自的相同指令,并根据用户定义的方向进行处理。默认指令只是将输入不加改变地回显到列表中\cytoks

请参阅以下文档和示例文档:https://ctan.org/pkg/tokcycle

已编辑以处理常规大括号参数语法。

\documentclass{article}
\usepackage{tokcycle}
\newif\ifvecnext
\stripgroupingtrue
\Characterdirective{\tctestifcon\ifvecnext
  {\addcytoks{\ensuremath{\vec{#1}}}}%
  {\addcytoks{#1}}%
  \vecnextfalse
}
\Groupdirective{\tctestifcon\ifvecnext
  {\addcytoks{\ensuremath{\vec{#1}}}}%
  {\groupedcytoks{\processtoks{#1}}}%
  \vecnextfalse
}
\Macrodirective{\tctestifx{\vec#1}
  {\vecnexttrue}%
  {\addcytoks{#1}}%
}\begin{document}
\tokencyclexpress \vec a,b,\vec{cx},d\endtokencyclexpress
\end{document}

在此处输入图片描述

要创建您自己的命名tokcycle环境,可以这样做:

\documentclass{article}
\usepackage{tokcycle}
\newif\ifvecnext
\stripgroupingtrue
\tokcycleenvironment\myscan% NEW TOKCYCLE ENVIRONMENT
{\tctestifcon\ifvecnext
  {\addcytoks{\ensuremath{\vec{##1}}}}%
  {\addcytoks{##1}}%
  \vecnextfalse
}% ↑ CHARACTER DIRECTIVE
{\tctestifcon\ifvecnext
  {\addcytoks{\ensuremath{\vec{##1}}}}%
  {\groupedcytoks{\processtoks{##1}}}%
  \vecnextfalse
}% ↑ GROUP DIRECTIVE
{\tctestifx{\vec##1}
  {\vecnexttrue}%
  {\addcytoks{##1}}%
}% ↑ MACRO DIRECTIVE
{\addcytoks{##1}}% ←DEFAULT SPACE DIRECTIVE
\begin{document}
\myscan \vec a,b,\vec{cx},d\endmyscan
\end{document}

补充

正如本答案的补充中所述,LaTeX3:以优雅的方式向前引用具有“未来”值的计数器,我正在努力改进软件包,以允许 tokcycle 指令直接访问未来的输入流。这将允许人们避免在由 Character 指令监视的 Macro 指令中设置标志的过程。(编辑:tokcycle[2021-05-27]已发布,因此\makeatletter代码已从此 MWE 中删除)

我设想了从输入流中弹出和推送标记的功能。您可以看到我完全避免使用 Character 指令。在\apply宏中,我使用了两个有趣的包宏,\groupedcytoks\tcpopliteral。在包文档中阅读有关它们的所有信息https://ctan.org/pkg/tokcycle。此处,\groupedcytoks用于在输出流中引入额外的组级别,即的参数\ensuremath。该宏\tcpopliteral用于从输入流中弹出一个参数,同时保留弹出标记的任何前导空格和分组(与正常的 TeX 吸收不同,正常的 TeX 吸收会从组的吸收中剥离前导空格以及 cat-1,2 标记)。

\documentclass{article}
\usepackage{tokcycle}
\Macrodirective{\ifx\vec#1\apply{#1}\else\addcytoks{#1}\fi}
\newcommand\apply[1]{\tcpopliteral\V\addcytoks{\ensuremath}%
  \groupedcytoks{\addcytoks{#1}\addcytoks[1]{\V}}}
\begin{document}
\tokencyclexpress \vec a,b,\vec{cx},d\endtokencyclexpress

\detokenize\expandafter{\the\cytoks}
\end{document}

在此处输入图片描述

相关内容