# How to do multiple string replacements?

I want to escape URL paths to obtain the percent-escaping that is also applied e.g. by browsers. For this purpose I tried to do the following (out-commented lines are meant to show what I'm aiming here):

\documentclass[a5paper]{article}
\usepackage{xstring}

\begin{document}

\newcommand{\urlescape}[1]{{%
\def\x{\StrSubstitute{#1}{\%}{\%25}}%
\def\x{\StrSubstitute{\x}{/}{\%2F}}%
% \def\x{\StrSubstitute{\x}{\&}{\%26}}%
% \def\x{\StrSubstitute{\x}{ }{\%20}}%
\expandafter\StrSubstitute\expandafter{\x}{+}{\%2b}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{,}{\%2c}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{:}{\%3a}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{;}{\%3b}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{?}{\%3f}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{@}{\%40}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{"}{\%22}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{<}{\%3c}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{>}{\%3e}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\#}{\%23}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\{}{\%7b}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\}}{\%7d}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{|}{\%7c}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\^}{\%5e}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\~}{\%7e}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{[}{\%5b}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{]}{\%5d}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\}{\%60}[\x]%
\x}}

\begin{document}

\urlescape{abcd/efgh\%foo\#bar baz}

\end{document}


Some syntactic sugar may be better:

\documentclass[a5paper]{article}
\usepackage{xstring}

\newcommand{\urlescapestep}[2]{%
\expandafter\StrSubstitute\expandafter{\x}{#1}{#2}[\x]%
}
\newcommand{\urlescape}[1]{{%
\noexpandarg % suppress expansions made by xstring
\StrSubstitute{#1}{\%}{\%25}[\x]% first step
\urlescapestep{/}{\%2F}%
\urlescapestep{\&}{\%26}%
\urlescapestep{ }{\%20}%
\urlescapestep{\\$}{\%24}%
\urlescapestep{+}{\%2b}%
\urlescapestep{,}{\%2c}%
\urlescapestep{:}{\%3a}%
\urlescapestep{;}{\%3b}%
\urlescapestep{?}{\%3f}%
\urlescapestep{@}{\%40}%
\urlescapestep{"}{\%22}%
\urlescapestep{<}{\%3c}%
\urlescapestep{>}{\%3e}%
\urlescapestep{\#}{\%23}%
\urlescapestep{\{}{\%7b}%
\urlescapestep{\}}{\%7d}%
\urlescapestep{|}{\%7c}%
\urlescapestep{\^}{\%5e}%
\urlescapestep{\~}{\%7e}%
\urlescapestep{[}{\%5b}%
\urlescapestep{]}{\%5d}%
\urlescapestep{\}{\%60}%
\x}}

\begin{document}

\urlescape{abcd/efgh\%foo\#bar baz}

\end{document}

• looks terrific! i'll try first thing tomorrow! – flow Jan 9 '14 at 18:22
• answers the question, but most of those don't need to be escaped in a url, and the replacements could be determined implicitly (as it's just the hex of the utf8 code) – David Carlisle Jan 9 '14 at 18:29
• @DavidCarlisle Yes, of course. That's left as an exercise to the reader. – egreg Jan 9 '14 at 18:39
• @egreg "You are defining \x in terms of itself, which is not a good thing to do"—to my understanding this is exactly what Don does on p215 of The TeX Book (edef\a{\double\a}`) – flow Jan 10 '14 at 14:02
• @DavidCarlisle you're in both respects; this list is a somewhat hypertrophic recommendation that i will like cut down somewhat. the reason it's being done in this simple-minded fashion is just for ease of implementation (and maybe performance); in a real programming language, i'd always use hexadecimal character codes. – flow Jan 10 '14 at 14:06