核心问题

核心问题

核心问题

如何处理由两个终止符之一分隔的文本?例如,如果我想处理到下一个的文本\A,我可以写

\def\CmdA#1\A{...}

但假设\A可能不存在,在这种情况下\B应该终止处理。有没有办法写一个命令

\def\CmdAB#1[\A|\B]{...} % Nonsense syntax

使得

\CmdAB\first\A\second\B

设置#1\first并留\second\B在输入流中,并且

\CmdAB\only\B

设置#1\only,并且在输入流中不留任何内容? \A应该优先于\B,这样

\CmdAB\other\B\order\A\after\B

设置#1\other\B\order并留\after\B在输入流中。

此外,由于我的目标是预处理文本然后使用它,我需要知道选择了哪一个\A或。\B


我尝试过的方法

我曾想过一次扫描一个标记,将扫描到的标记保存在标记寄存器中以供以后处理,并在看到任一结束标记时停止扫描,但我无法让它工作。我编写了一些更简单的代码,用于\let从输入中挑选字符,检查单个终止符,并在此过程中将其添加到标记寄存器中,但这不起作用,因为\let控制序列不会扩展。代码如下:

\newtoks\ScanToks
\newcommand*{\AddTok}[1]{\ScanToks\expandafter{\the\ScanToks#1}}

\newcommand*{\QScan}{\QScan}
\newcommand*{\Scan}{\afterassignment\DoScan\let\Scanned=}
\newcommand*{\DoScan}{%
  \ifx\Scanned\QScan\else
    \expandafter\AddTok\Scanned
    \expandafter\Scan
  \fi
}

这看起来不错,似乎在运行它时可以正常工作,但是从输出结果来看,它并不完全正常工作:

*\Scan 1 2 3 \QScan

*\showthe\ScanToks
> \Scanned \Scanned \Scanned .

一旦你思考了这个问题(并且读了正确的部分TeXbook和正确的 TeX.SE 问题),这让人感到沮丧;如果我们有\let\a=1\let\b=\a,那么我们怎么可能知道\a应该“扩展”成1\b应该“扩展”成\a?但不幸的是,我看不出有办法编写一个\def只从输入流中吸收一个标记的。如果\def取任意平衡的文本,我可能可以处理它,但相反\def 需要一个支撑组,否则将事物解析为参数规范的一部分。

另外,此\Scan命令不处理空格,但相比之下,这只是小事一桩。


动机

我正在尝试编写一个处理align-like 环境第一行的命令。此命令需要:

  1. 吸收代币直到第一个\\
  2. 处理这些标记(即,计算“&”符号以确定列数)。
  3. 将这些标记放回输入流中,前面是计算的信息(即列数)。

但是,\\如果环境只有一行长,分隔符可能不存在;在这种情况下,我需要处理整个环境,直到完成\end{EnvName}(其余部分都相同)。但在环境开始时,我不知道这两种情况中的哪一种,所以我想向前扫描到下一个\\ 或者\end{EnvName}从而引发这个问题)。

答案1

这是一种可能的方法。

它的工作原理是首先读取整个环境主体,然后提取第一行。

调用之后\getfirstline,整个环境的内容在 中可用\BODY,第一行的内容在 中\firstline

\documentclass{article}
\usepackage{environ}

\NewEnviron{foo}
{%
  \expandafter\getfirstline\BODY\\\@nil
  \show\firstline
}

\def\getfirstline#1\\#2\@nil
{%
  \def\firstline{#1}%
}

\begin{document}

\begin{foo}
  first line
\end{foo}

\begin{foo}
  first line\\
  second line
\end{foo}

\end{document}

相关内容