替换子字符串

替换子字符串

这实际上是替换子字符串从6年前开始。

我想替换长字符串中的子字符串。使用\ReplaceStr使用字符串-package 这样做很好。但是,如果我想多个这样的函数,我得到错误Use of \@xs@StrSubstitute@@ doesn't match its definition. \ReplaceStrB{\ReplaceStr{aXYbXYc}}

任何评论和解决方法都非常感谢。我知道如何替换 LaTeX 之外的字符串。但是,在这个特定情况下,我需要一个仅限 LaTeX 的解决方案。

\documentclass{article}
\usepackage{xstring}
\newcommand{\ReplaceStrX}[1]{\StrSubstitute{#1}{X}{Y}}
\newcommand{\ReplaceStrB}[1]{\StrSubstitute{#1}{b}{B}}

\begin{document}
\ReplaceStrX{aXbXc}                    % produces aYbYc
\ReplaceStrB{aXbXc}                    % produces aXBXc
\ReplaceStrB{\ReplaceStrX{aXbXc}}      % should produce aYBYc
\end{document}

编辑 1:简单的解决方案

只需按照 Manuel 的建议添加即可\noexpandarg\exploregroups。这对我的问题有用。在其他情况下,还可以查看 Manuel 的宏解决方案或 cfr 的 13regex 解决方案。

编辑2:相关问题

以下成功生成aXBXc

\ReplaceStrB{aXbXc}

然而这并不起作用。

\def\tempvar{aXbXc}
\ReplaceStrB{\tempvar}

有什么想法吗,如何将其\tempvar作为字符串安全地保存?

答案1

从我的回答来看这里,您可以使用这些宏来执行此操作。(我将使用第二个版本,因为命名空间已经是freplace而不是hmenke,但第一个版本也可以正常工作。)

\documentclass{scrartcl}

\usepackage{xparse}

\ExplSyntaxOn

\cs_generate_variant:Nn \cs_generate_variant:Nn { c }

\NewDocumentCommand \setfreplace { +m +m }
 {
  \freplace_set:nn { #1 } { #2 }
 }
\DeclareExpandableDocumentCommand \freplace { +m +m +m }
 {
  \freplace:nnn { #1 } { #2 } { #3 }
 }
\quark_new:N \q_freplace
\quark_new:N \q_freplacestop
\cs_new:Npn \freplace:nnn #1 #2 #3
 {
  \exp_not:f { \use:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } ):n } { #3 } }
 }
\cs_new_protected:Npn \freplace_set:nn #1 #2
 {
  \cs_set:cpx { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } ):n } ##1
   {
    \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxi:nw } { } ##1 { \exp_not:N \q_freplace }
   }
  \cs_set:cpx { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxi:nw } ##1 ##2 ##
   {
    \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_nobraces:nfn }
     { ##1 } { \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_do:n } { ##2 } }
   }
  \cs_set:cpx { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_nobraces:nnn } ##1 ##2
   {
    \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxii:nn } { ##1 ##2 }
   }
  \cs_generate_variant:cn { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_nobraces:nnn } { nf }
  \cs_set:cpx { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxii:nn } ##1 ##2
   {
    \exp_not:N \str_if_eq:nnTF { \exp_not:N \q_freplace } { ##2 }
     { \exp_stop_f: ##1 }
     {
      \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_addbraces:nfw }
       { ##1 } { \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } ):n } { ##2 } }
     }
   }
  \cs_set:cpx { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_addbraces:nnw } ##1 ##2
   {
    \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxi:nw } { ##1 { ##2 } }
   }
  \cs_generate_variant:cn { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_addbraces:nnw } { nf }
  \cs_set:cpx { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_do:n } ##1
   {
    \exp_not:N \tl_if_empty:nTF { ##1 }
     { \exp_stop_f: }
     {
      \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxiii:nww }
       { } ##1 \exp_not:n { #1 \q_freplace \q_freplacestop }
     }
   }
  \cs_set:cpx { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxiii:nww } ##1 ##2 #1 ##3 \q_freplacestop
   {
    \exp_not:N \str_if_eq:nnTF { \exp_not:N \q_freplace } { ##3 }
     { \exp_stop_f: ##1 ##2 }
     {
      \exp_not:c { freplace_( \tl_to_str:n { #1 } )_( \tl_to_str:n { #2 } )_auxiii:nww }
       { ##1 ##2 \exp_not:n { #2 } } ##3 \exp_not:N \q_freplacestop
     }
   }
 }

\cs_generate_variant:Nn \freplace:nnn { nnV }
\cs_new_protected:Npn \tl_replace_nested:Nnn #1 #2 #3
 {
  \freplace_set:nn { #2 } { #3 }
  \tl_set:Nx #1 { \freplace:nnV { #2 } { #3 } #1 }
 }

\ExplSyntaxOff

\setfreplace{X}{Y} % these two lines are mandatory, for each \freplace you use
\setfreplace{b}{B} % in the document, you have to first declare it with \setfreplace

\newcommand\ReplaceStrX[1]{\freplace{X}{Y}{#1}}
\newcommand\ReplaceStrB[1]{\freplace{b}{B}{#1}}

\begin{document}

\ReplaceStrX{aXbXc} produces aYbYc\par
\ReplaceStrB{aXbXc} produces aXBXc\par
\ReplaceStrB{\ReplaceStrX{aXbXc}} should produce aYBYc\par

\end{document}

这不仅适用于嵌套括号,而且确实是一个可扩展的解决方案。此版本使用语法\freplace{search}{replace}{token list where you search},并要求您为所使用的每个不同的搜索和替换发出一个\setfreplace{search}{replace}(以创建所需的宏)。

我链接的答案中的另一个版本使用的语法\freplace{name}{token list to replace}是,你必须在前面写上\setfreplace{name}{search}{replace},即给该对一个符号名称。如果你喜欢这种语法,请从答案的第一部分复制代码。


无论如何,这段代码似乎可以编译

\documentclass{scrartcl}

\usepackage{xstring}

\noexpandarg\exploregroups
\newcommand\ReplaceStrX[1]{\StrSubstitute{#1}{X}{Y}}
\newcommand\ReplaceStrB[1]{\StrSubstitute{#1}{b}{B}}

\begin{document}

\ReplaceStrX{aXbXc}\ produces aYbYc\par
\ReplaceStrB{aXbXc}\ produces aXBXc\par
\ReplaceStrB{\ReplaceStrX{aXbXc}}\ should produce aYBYc\par

\end{document}

答案2

使用新包的版本l3regex(我相信它目前是实验性的)。

\documentclass{article}
\usepackage{l3regex,xparse}
\ExplSyntaxOn
\tl_new:N \l_lab_string_tl
\cs_new_protected:Nn \lab_replace_me:nnn
{
  \tl_set:Nn \l_lab_string_tl { #3 }
  \regex_replace_all:nnN { #1 } { #2 } \l_lab_string_tl
  \l_lab_string_tl
}
\NewDocumentCommand \ReplaceStrX { +m }
{
  \group_begin:
  \lab_replace_me:nnn { X } { Y } { #1 }
  \group_end:
}
\NewDocumentCommand \ReplaceStrB { +m }
{
  \group_begin:
  \lab_replace_me:nnn { b } { B } { #1 }
  \group_end:
}
\ExplSyntaxOff

\begin{document}
\ReplaceStrX{aXbXc}                    % produces aYbYc
\ReplaceStrB{aXbXc}                    % produces aXBXc
\ReplaceStrB{\ReplaceStrX{aXbXc}}      % should produce aYBYc
\end{document}

字符串替换

答案3

StrSubstitute命令实际上有一个最终的可选参数来处理这个问题。此参数允许您为替换结果提供一个名称。结果随后将存储在具有此名称的命令中,该命令可以传递给StrSubstitute您希望执行的下一个命令(或其他类似xstring命令)。

例如,您可以像这样进行双重替换:

\StrSubstitute{aXbXc}{X}{Y}[\afterXtoY]\StrSubstitute{\afterXtoY}{b}{B}

如果您想创建执行每个替换的新命令,并且不介意创建第三个命令来首先执行 X 到 Y 的替换,然后执行 b 到 B 的替换,而不是只有两个命令,那么这将起作用:

\documentclass{article}

\usepackage{xstring}
\newcommand{\ReplaceStrX}[1]{\StrSubstitute{#1}{X}{Y}}
\newcommand{\ReplaceStrB}[1]{\StrSubstitute{#1}{b}{B}}
\newcommand{\ReplaceStrBX}[1]{\StrSubstitute{#1}{X}{Y}[\afterReplaceStrX]\StrSubstitute{\afterReplaceStrX}{b}{B}}

\begin{document}

\ReplaceStrX{aXbXc}                    % produces aYbYc
\ReplaceStrB{aXbXc}                    % produces aXBXc
\ReplaceStrBX{aXbXc}                   % produces aYBYc

\end{document}

如果您只想要两个命令,那么这是可行的(尽管现在在单独{}使用该命令时您需要输入额外的命令):\ReplaceStrX

\documentclass{article}

\usepackage{xstring}
\newcommand{\ReplaceStrX}[2]{\StrSubstitute{#1}{X}{Y}[#2]}
\newcommand{\ReplaceStrB}[1]{\StrSubstitute{#1}{b}{B}}

\begin{document}
\ReplaceStrX{aXbXc}{}                    % produces aYbYc
\ReplaceStrB{aXbXc}                    % produces aXBXc

\ReplaceStrX{aXbXc}{\afterReplaceStrX}\ReplaceStrB{\afterReplaceStrX} % produces aYBYc

\end{document}

当然,您可以执行相同的操作来\ReplaceStrB获得可以按任意顺序一起使用的一对命令(在您的示例中,这会产生相同的结果,但在此示例中,使用不同的替换命令则不会):

\documentclass{article}
\usepackage{xstring}
\newcommand{\ReplaceStrX}[2]{\StrSubstitute{#1}{X}{bd}[#2]}
\newcommand{\ReplaceStrB}[2]{\StrSubstitute{#1}{b}{Xb}[#2]}
%\newcommand{\ReplaceStrBX}[1]{\StrSubstitute{#1}{X}{Y}[\afterReplaceStrX]\StrSubstitute{\afterReplaceStrX}{b}{B}}

\begin{document}

\ReplaceStrX{aXbc}{}                    % produces abdbc
\ReplaceStrB{aXbc}{}                    % produces aXXbc

\ReplaceStrX{aXbc}{\afterReplaceStrX}\ReplaceStrB{\afterReplaceStrX}{} % produces aXbdXbc 
\ReplaceStrB{aXbc}{\afterReplaceStrB}\ReplaceStrX{\afterReplaceStrB}{} % produces abdbdbc

\end{document}

相关内容