如何使用 regexpatch 用控制序列修补宏

如何使用 regexpatch 用控制序列修补宏

我用 修补宏已部分成功regexpatchcmd。我想修补一个调用另一个宏的宏。目的是修补后的宏中的每个命令都变成宏内\string\ttfamily除了宏包含@符号时​​,它都可以工作。

梅威瑟:

\documentclass{article}
\usepackage{regexpatch}
\tracingxpatches
\begin{document}
\def\testone{test \Test \tESt \@Test \Te@st}
\def\testtwo{\Test \tESt \@Test \Te@st}
\regexpatchcmd*{\testone}{\c{[a-zA-Z@]*}}{\c{begingroup}\c{ttfamily}\c{string}\0\c{endgroup}}{}{}
\regexpatchcmd*{\testtwo}{\c{[a-zA-Z@]*}}{\c{begingroup}\c{ttfamily}\c{string}\0\c{endgroup}}{}{}
\show\testone
\show\testtwo
\testone -- \testtwo
\end{document}

这两个命令都是可修补的(根据\trackingxpatches,因此这没有问题)。 的输出\show\testone是:

> \testone=macro:
->test \begingroup \ttfamily \string \Test \endgroup
\begingroup \ttfamily \string \tESt \endgroup
\begingroup \ttfamily \string \@\endgroup
Test
\begingroup \ttfamily \string \Te \endgroup @st

在处理时\@Test,为什么我们有\@在组内 Test外面?那么为什么正则表达式的匹配停止在@

修补时也会发生类似的情况\Te@st:只有\Te匹配,但@st没有匹配。在这种情况下,对正则表达式的扫描在 之前停止@

宏显示了不同的行为。以下几行是MWE 上\testtwo该行的输出:\show\testtwo

> \testtwo=macro:
->\Test \tESt
\begingroup \ttfamily \string \@\endgroup Test
\begingroup \ttfamily \string \Te \endgroup @st.

它对符号的行为相同。和宏@之间的区别在于前面附加的单词。 如果没有该单词(如),则编写的正则表达式不会匹配前两个命令(和)。 为什么?\testone\testtwotest\testtwo\Test\tESt

我想了解正则表达式中的错误。

附注:由于regexpatch.sty会加载l3regex.sty并发出警告以使用expl3而不是l3regex,因此regexpatch.sty应更新为使用expl3

答案1

TeX 适用于标记。您的\testone宏有一个由 17 个标记组成的替换文本

t•e•s•t• •\Test•\tESt•\@•T•e•s•t• •\Te•@•s•t

(我用它来分隔标记)。与您的搜索表达式匹配的标记是数字 6、7、8 和 14。

如果定义当是一个字母时就会发生替换@,因为在这种情况下标记只有九个,例如\Te@st在定义时被视为单个标记。

然而,当是字母时也必须执行替换@,否则重建宏将不会成功(此限制可能会在 的未来版本中取消regexpatch)。

请注意,您可以创建一个更短的搜索表达式:

\documentclass{article}
\usepackage{regexpatch}

\newcommand{\stringify}[1]{\texttt{\string#1}}

\begin{document}

\makeatletter
\def\testone{test \Test \tESt \@Test \Te@st}
\def\testtwo{\Test \tESt \@Test \Te@st}

\regexpatchcmd*{\testone}
  {\cC.}
  {\c{stringify}\0}
  {}{}

\testone

\makeatother

\end{document}

搜索表达式\cC与控制序列匹配,因此\cC.匹配单个控制序列。在控制序列前添加前缀\stringify比在其前后添加标记更容易。

答案2

您是否只想将所有内容包装在\makeatletter...中?如果您在文档中\makeatother使用宏名称,而不是在类或包文件中,则需要这样做。(在类和包文件中,已经是字母。)如果没有这个,是 宏后跟字母,是 宏后跟字母。但是,当 被视为字母时,是 宏,是单个宏。@@\@Test\@Test\Te@st\Te@st@\@Test\@Test\Te@st\Te@st

\documentclass{article}
\usepackage{regexpatch}
\tracingxpatches
\begin{document}
\makeatletter
\def\testone{test \Test \tESt \@Test \Te@st}
\def\testtwo{\Test \tESt \@Test \Te@st}
\regexpatchcmd*{\testone}{\c{[a-zA-Z@]*}}{\c{begingroup}\c{ttfamily}\c{string}\0\c{endgroup}}{}{}
\regexpatchcmd*{\testtwo}{\c{[a-zA-Z@]*}}{\c{begingroup}\c{ttfamily}\c{string}\0\c{endgroup}}{}{}
\makeatother
\show\testone
\show\testtwo
\testone -- \testtwo
\end{document}

结果

答案3

感谢@cfr 和@egreg 的澄清,我已经修复了之前提到的实际情况中的问题。我在写这个新的 MWE 之前就修复了这个问题,它基本上展示了@cfr 和@egreg 指出的内容,即当 with是字母\regexpatch时也必须执行。@

昨天我写道这种情况发生在类内的代码中;我错了。 MWE 中显示的情况发生在 的文档部分.dtx,那么@就不是字母,而且\makeatletter确实是必需的。新的 MWE 是:

\documentclass{article}
\usepackage{regexpatch,catchfilebetweentags}

\newcommand{\stringify}[1]{\texttt{\string#1}}
\newcommand{\catch}{
 \catcode`\<=12
 \catcode`\>=12
 \makeatletter
 \CatchFileBetweenDelims{\testone}{test}{<}{>}[\catcode13=14\makeatletter]
 \regexpatchcmd*{\testone}{\cC.}{\c{stringify}\0}{}{}
 \makeatother
 \catcode`\<=13
 \catcode`\>=13
}

\begin{document}
 \catch
 \testone
\end{document}

文件内容test例如:

<
\Test
\@Test
\Te@st
>

当然,为了 MWE 的目的,我用 替换了\CatchFileBetweenDelims测试定义\def(错误地没有\makeatletter)。此宏的可选参数旨在成为一些“起始”代码,如 catcode 更改。当未指定此可选参数时,默认值为\makeatletter。我指定了这个可选参数,但没有考虑到默认值\makeatletter已被覆盖并且需要在那里指定(就像在这个新的 MWE 中一样)。

\makeatletter在修补命令之前我没有尝试过,这是另一个重要的修复,让我完成dtx并提交新版本。

我写这个答案是为了完整性,但有了你的答案就足够了。再次感谢@cfr 和@egreg。

相关内容