环境启动宏的问题

环境启动宏的问题

出于某种原因,我想要一个宏\BeginControl,它\BeginControl{\environment}相当于\begin{environment}。我整理了一些代码。它通常可以工作,但我正在尝试解决星号环境的问题。

考虑以下代码。align*环境的两个实例应该表现相同,但它会产生一个错误的错误。! LaTeX Error: \begin{align*} on input line 33 ended by \end{align*}.问题出在哪里?

\documentclass{article}

\usepackage{amsmath}

\newcommand*{\cdef}{\newcommand*}

\cdef \Expanded [1]{%
    \begingroup
    \edef \x {%
        \endgroup
        #1%
    }%
    \x
}
\cdef \Apply [1]{%
    \Expanded{\noexpand #1}%
}
\cdef \IgnoreNext [1]{%
    % ignore next token
}
\cdef \MacroName [1]{%
    \expandafter\IgnoreNext \string#1%
}
\cdef \BeginControl [1]{%
    \Apply{\begin{\MacroName{#1}}}%
}

\begin{document}
    \begin{align*}
        A \\
        B
    \end{align*}
    \BeginControl{\align*}
        A \\
        B
    \end{align*}
\end{document}

更新:感谢答案,我发现我的宏\MacroName不正确,因为它扩展为带有 catcode 12 而不是 11 的宏名称\string。以下定义应该有效:

\let \Ex \expandafter
\cdef \ExEx {%
    \Ex\Ex\Ex
}
\cdef \ExExArg [2]{%
    \ExEx#1\ExEx{#2}%
}
\cdef \MacroName [1]{%
    \ExExArg\scantokens{\Ex\IgnoreNext \string#1\noexpand}%
}

答案1

让我们看看会发生什么

\BeginControl{\align}

步骤 1:扩展\BeginControl

\Apply{\begin{\MacroName{\align}}}

第 2 步:扩展\Apply

\Expanded{\noexpand\begin{\MacroName{\align}}}

步骤 3:扩展\Expanded

\begingroup\edef\x{\endgroup\noexpand\begin{\MacroName{\align}}}\x

步骤4:\begingroup执行;打开一个组并删除命令。

步骤 5:\edef导致给定的完全扩展平衡文本

子步骤5.1:\endgroup不可扩展,将其推入待构建的token列表中。

子步骤 5.2:\noexpand使下一个标记不可扩展;将其移除并推送到\begin正在构建的标记列表中。

子步骤 5.3:{不可展开,请推动它。

子步骤 5.4:扩展\MacroName

\expandafter\IgnoreNext\string\align

子步骤 5.5:\expandafter扩展\string并删除。请注意,\string\align产生\align字符所有具有类别代码12.

子步骤 5.6:扩展\IgnoreNext;反斜杠已被删除。

子步骤 5.7-5.11:令牌align不可扩展;将它们推送到正在构建的令牌列表中。

子步骤 5.12:}不可扩展,请推动它

步骤 6:标记列表是\endgroup\begin{align};TeX 执行\def\x{\endgroup\begin{align}}

步骤 7:展开,用上面的标记列表\x替换。\x

第八步:\endgroup关闭已打开的群组,含义\x忘记了。

步骤9:\begin{align}执行。

看起来它应该能起作用;但可惜不能。

请记住,align是具有类别代码 12 的字符串;当 LaTeX 执行时,\begin{align}它会设置\@currenviralign(所有类别代码 12);的执行\end{align}会将参数与进行比较\@currenvir,结果不同,因为\end{align}字符的类别代码为 11。

您可以检查

\expandafter\begin\expandafter{\string minipage}{25pt}
xyz
\end{minipage}

给出相同的错误:只有类别代码 12,但这足以使和m处的两个“字符串”有所不同。\begin\end

错误已经解释过了;我不确定你采用如此复杂的方法的目的是什么。


一个办法。

\documentclass{article}

\usepackage{amsmath}

\makeatletter
\newcommand{\BeginControl}[1]{%
  \begingroup
  \edef\x{\expandafter\@gobble\string#1}%
  \edef\x{\endgroup\noexpand\begin{\scantokens\expandafter{\x\noexpand}}}%
  \x
}
\makeatother

\begin{document}

\BeginControl{\enumerate}
\item xyz
\end{enumerate}

\BeginControl{\align}
  A \\
  B
\end{align}

\BeginControl{\align*}
  A \\
  B
\end{align*}

\end{document}

使用通常的类别代码重新读取\scantokens字符串。

答案2

您的问题是 LaTeX 检查了 中的 strigs+catcodes 的等价性\@endcheck,因为\ifx使用了 。正常类型的环境中有 catcode 为 11 的字母,其他字符为 12,但 生成的字符串\string有 catcode 为 12 的字母。

您必须将字符串重新 catcode 为 catcodes 11。我建议基于以下内容使用类似的可扩展宏\ifcase

\documentclass{article}

\usepackage{amsmath}

\def\recatcode#1{\ifx#1\relax\else
  \ifcase\numexpr`#1-`A\relax A\or B\or C\or D\or E\or F\or G\or H\or I\or
      J\or K\or L\or M\or N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or
      X\or Y\or Z\or#1\or#1\or#1\or#1\or#1\or#1\or
      a\or b\or c\or d\or e\or f\or g\or h\or i\or
      j\or k\or l\or m\or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or 
      x\or y\or z\else #1\fi
  \expandafter\recatcode\fi
}
\def\BeginControl#1{\edef\x{\expandafter\ignoreone\string#1}%
  \edef\x{\expandafter\recatcode\x\relax}%
  \expandafter\begin\expandafter{\x}%
}
\def\ignoreone#1{}

\begin{document}  
    \begin{align*}
        A \\
        B
    \end{align*}

    \BeginControl{\align}
        A \\
        B
    \end{align}
\end{document}

相关内容