Command which replaces all occurrences of a certain character with another character?
Use 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}
What's the advantage? You can easily generalize your command using the same idea.
\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}
One way would be to use \StrSubstitute
from the xstring
package:
Code:
\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}
Another solution using only TeX primitives:
\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}
Edit: I'll try to explain how it works. IMHO, it is more valuable to know how TeX works inside than only usage the code or package without thinking.
First line defines \addto<macro>{<text>}
which adds to the <macro>
the <text>
. For example after \def\a{xx} \addto\a{yy}
we have \a
defined as xxyy
.
The \replacestrings{<string1>}{<string2>}
replaces all occurrences of <string1>
in the \tmpb
macro to the <string2>
. First, the \tmp
macro is defined at line 3 as:
\def\tmp#1<string1>#2\end{...}
Second, the \tmp
is executed with expanded \tmpb
as a parameter followed by \end
. The \tmpb
is (1) expanded, (2) it is set to empty and (3) the \tmp
is executed. This is the reason of 5x \expandafter
in line 4.
Suppose, we have \def\tmpb{abXXcdXXef}
and we run \replacestring{XX}{YY}
. Then \tmp
is declared as the following pseudocode:
\def\tmp#1XX#2\end{if #2 is empty: \addto\tmpb{#1}
else: \addto\tmpb{#1YY}
\tmp #2\end
fi}
Then \tmp aaXXcdXXefXX\end
is executed, but the \tmpb
is set to empty first.
The \tmp
expands with #1=aa
, #2=cdXXefXX
. Because #2
isn't empty, the
\addto\tmpb{aaYY} \tmp cdXXefXX\end
is executed. So, \tmpb
includes aaYY
. The second run of \tmp
expands with #1=cd
#2=efXX
to
\addto\tmpb{cdYY} \tmp efXX\end
Now, \tmpb
includes aaYYcdYY
. The third run of \tmp
expands with #1=ef
and #2
empty to
\addto\tmpb{ef}
This gives the result in \tmpb
aaYYcdYYef
.
An attentive reader can give notice that there is a bug: if the replaced text ends with one X
, for example \def\tmpb{aaXXbbX}
and <string1>
is XX
then there is a problem. It is true, but the question in this thread demands to replace only one token to one token. The real \replacestrings
(used in OPmac, for example) does one more step: adds the special token at the end of the replaced text, then does the replacement and then removes this special token.