我有一些文本,我想使用xstring
的\StrSubstitute
方法进行预处理(基本上是用简单的命令(如foobar
by )替换某些关键字\emph{foobar}
)。有两个附带条件使这变得困难(至少我还没能弄清楚如何做到这一点)。一方面,我需要在模式\StrSubstitute
下运行noexpandarg
,另一方面,我想使用活动空格来打印出遵循空格的输入。我知道有诸如listings
或 之类的环境verbatim
,但这些环境不符合我的想法:最终,这样预处理的字符串应该进入 ( amsmath
)align
环境。
这就是我所拥有的
\documentclass{article}
\usepackage{xstring}
\begingroup
\catcode`\@=\active
\lccode`\@=`\ % At-sign is a space
\lowercase{%
\endgroup
\newenvironment{withspaces}{%
\catcode`\ =\active % Space active
\let@=~%
}{
}}
\begin{document}
\def\foo{foo}
\begin{withspaces}
There is space before \foo foo
\end{withspaces}
\begin{withspaces}
\StrSubstitute{There is space before \foo foo}{foo}{bar}
\end{withspaces}
\noexpandarg % in order to first run the string substitution and only then expand \foo
\StrSubstitute{There is space before \foo foo}{foo}{bar}
% The following breaks down to the noexpandarg flag
\begin{withspaces}
%\StrSubstitute{There is space before \foo foo}{foo}{bar}
\end{withspaces}
\end{document}
环境withspaces
(改编自 Joseph 的回答遵循空间的环境) 似乎在文本模式和数学模式下都能正常工作。 第一次使用 时的效果\StrSubstitute
与 中相同fullyexpandmode
。 但是,结果是首先\foo
扩展 ,然后替换为 ,\StrSubstitute
这就是为什么我认为我需要使用noexpandarg
:\StrSubstitute
应该进行替换而不扩展\foo
。
单独来看,这个方法也很好用。也就是说,
\noexpandarg % in order to first run the string substitution and only then expand \foo
\StrSubstitute{There is space before \foo foo}{foo}{bar}
得到所需的结果,但没有活动空格。一旦我尝试将两者结合起来(取消注释\StrSubstitute
MWE 中的最后一个),我就陷入了
Argument of \@xs@behindspace has an extra }.
<inserted text>
\par
l.33 \end
{withspaces}
这就是我迷失的地方。
答案1
您可能需要查看使用以下方法的实现l3regex
:
\documentclass{article}
\usepackage{xstring}
\usepackage{xparse}
% \usepackage{l3tl-analysis} % uncomment for debugging
\newenvironment{withspaces}
{\obeyspaces\begingroup\lccode`~=` \lowercase{\endgroup\let~}~}
{}
\ExplSyntaxOn
\tl_new:N \l_arno_strsub_input_tl
\tl_new:N \l_arno_strsub_search_tl
\tl_new:N \l_arno_strsub_replace_tl
\NewDocumentCommand{\strsub}{mmm}
{
\tl_set:Nn \l_arno_strsub_input_tl { #1 }
\tl_set:Nn \l_arno_strsub_search_tl { #2 }
\tl_set:Nn \l_arno_strsub_replace_tl { #3 }
\regex_replace_all:nnN
{ \u{l_arno_strsub_search_tl} }
{ \u{l_arno_strsub_replace_tl} }
\l_arno_strsub_input_tl
%\tl_show_analysis:N \l_arno_strsub_input_tl % uncomment for debugging
\tl_use:N \l_arno_strsub_input_tl
}
\ExplSyntaxOff
\begin{document}
\def\foo{foo}
\begin{withspaces}
There is space before \foo foo
\end{withspaces}
\begin{withspaces}
\strsub{There is space before \foo foo}{foo}{bar}
\end{withspaces}
\strsub{There is space before \foo foo}{foo}{bar}
\begin{withspaces}
\strsub{Some spaces \foo foo}{foo}{\textbf{foo}}
\end{withspaces}
\end{document}
搜索和替换字符串存储在标记列表中,因此它们可以“按原样”用于正则表达式业务。
正如您在最后一个例子中看到的,只有的明确外观foo
被替换了。
如果取消注释标记为“用于调试”的行,您将在终端中看到正则表达式替换后的字符串表示。
(对于 TeX Live 2017 之前的版本,您还需要\usepackage{l3tl-analysis}
和\usepackage{l3regex}
才能\usepackage{xparse}
使用此功能。)
答案2
您可以定义\dospaces
为宏的前缀\StrSubstitute
:
\def\dospaces\StrSubstitute{\bgroup\catcode`\ =13 \let\protect=\noexpand \dospacesA}
\def\dospacesA#1{\xdef\tmp{#1}\egroup \expandafter\StrSubstitute\expandafter{\tmp}}
%% usage:
\dospaces\StrSubstitute{There is space before \foo foo}{foo}{bar}