我用 修补宏已部分成功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
\testtwo
test
\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。