如何定义一个命令,将其参数中某个字符的每个实例替换为另一个特定字符?
例如,我想定义一个命令,通过将 every 替换为来\myreplace{1-2-abc-345}
给出输出。1.2.abc.345
-
.
答案1
使用expl3
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\myreplace}{m}
{
\tl_set:Nn \l__maxd_argument_tl { #1 }
\tl_replace_all:Nnn \l__maxd_argument_tl { - } { . }
\tl_use:N \l__maxd_argument_tl
}
\tl_new:N \l__maxd_argument_tl
\ExplSyntaxOff
\begin{document}
\myreplace{1-2-abc-345}
\end{document}
有什么好处?你可以很容易地用同样的想法来概括你的命令。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\myreplace}{ O{} m }
{
\maxd_replace:nn { #1 } { #2 }
}
\tl_new:N \l__maxd_argument_tl
\cs_new_protected:Npn \maxd_replace:nn #1 #2
{
\group_begin:
\tl_set:Nn \l__maxd_argument_tl { #2 }
\keys_set:nn { maxd/replace } { #1 }
\tl_replace_all:NVV \l__maxd_argument_tl \l_maxd_search_tl \l_maxd_replace_tl
\tl_use:N \l__maxd_argument_tl
\group_end:
}
\cs_generate_variant:Nn \tl_replace_all:Nnn { NVV }
\keys_define:nn { maxd/replace }
{
search .tl_set:N = \l_maxd_search_tl,
search .initial:n = { - },
replace .tl_set:N = \l_maxd_replace_tl,
replace .initial:n = { . }
}
\ExplSyntaxOff
\begin{document}
\myreplace{1-2-abc-345}
\myreplace[replace=--]{1-2-abc-345}
\myreplace[search=2,replace=0]{1-2-abc-345}
\end{document}
答案2
一种方法是\StrSubstitute
使用包裹xstring
:
代码:
\documentclass{article}
\usepackage{xstring}
\newcommand{\myreplace}[2]{%
\StrSubstitute{#2}{-}{.}[#1]%
}%
\begin{document}
\myreplace{\NewValue}{1-2-abc-345}
input: 1-2-abc-345
output: \NewValue
\end{document}
答案3
仅使用 TeX 基元的另一种解决方案:
\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\replacestrings#1#2{%
\def\tmp##1#1##2\end{\ifx\end##2\end\addto\tmpb{##1}\else\addto\tmpb{##1#2}\tmp##2\end\fi}%
\expandafter\def\expandafter\tmpb\expandafter{\expandafter}\expandafter\tmp\tmpb#1\end
}
\def\myreplace#1{\def\tmpb{#1}\replacestrings{-}{.}\tmpb}
\myreplace{1-2-abc-345}
编辑:我会尝试解释怎么运行的. 在我看来,了解 TeX 内部如何运作比不假思索地使用代码或包更有价值。
第一行定义了\addto<macro>{<text>}
添加到<macro>
。<text>
例如,在\def\a{xx} \addto\a{yy}
我们\a
定义为之后xxyy
。
将宏中\replacestrings{<string1>}{<string2>}
的所有出现的替换为。首先,宏在第 3 行定义为:<string1>
\tmpb
<string2>
\tmp
\def\tmp#1<string1>#2\end{...}
其次,\tmp
执行 ,并将 扩展\tmpb
为参数,后跟\end
。\tmpb
(1) 扩展 , (2) 将其设置为空, (3)执行 。这就是第 4 行中\tmp
5x 的原因。\expandafter
假设,我们有\def\tmpb{abXXcdXXef}
并且运行\replacestring{XX}{YY}
。然后\tmp
声明为以下伪代码:
\def\tmp#1XX#2\end{if #2 is empty: \addto\tmpb{#1}
else: \addto\tmpb{#1YY}
\tmp #2\end
fi}
然后\tmp aaXXcdXXefXX\end
执行,但\tmpb
首先将设置为空。使用、\tmp
展开#1=aa
。#2=cdXXefXX
由于#2
不为空,因此
\addto\tmpb{aaYY} \tmp cdXXefXX\end
执行。因此,\tmpb
包括aaYY
。第二次运行\tmp
扩展#1=cd
#2=efXX
为
\addto\tmpb{cdYY} \tmp efXX\end
现在,\tmpb
包括aaYYcdYY
。第三次运行的\tmp
扩展为#1=ef
和#2
空的
\addto\tmpb{ef}
这给出了结果\tmpb
aaYYcdYYef
。
细心的读者会注意到有一个错误:如果替换的文本以一个结尾X
,例如\def\tmpb{aaXXbbX}
,则<string1>
存在XX
问题。这是真的,但此线程中的问题要求仅将一个标记替换为一个标记。实际\replacestrings
(例如,在 OPmac 中使用)执行了更多步骤:在替换文本的末尾添加特殊标记,然后进行替换,然后删除此特殊标记。
答案4
我想定义一个命令
\myreplace{1-2-abc-345}
,1.2.abc.345
通过将每个-
命令替换为.
这是一个基于LuaLaTeX的解决方案,它利用了Lua强大的gsub
字符串功能。
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
function myreplace ( s )
return ( unicode.utf8.gsub ( s , "-", "." ) )
end
\end{luacode}
\newcommand\myreplace[1]{\directlua{myreplace(\luastringN{#1})}}
\begin{document}
\myreplace{1-2-abc-345}
\end{document}