这实际上是替换子字符串从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}