我想转义 URL 路径以获得浏览器等也应用的百分比转义。为此,我尝试执行以下操作(注释掉的行是为了显示我在这里的目标):
\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}}%
% \def\x{\StrSubstitute{\x}{\$}{\%24}}%
% \def\x{\StrSubstitute{\x}{+}{\%2b}}%
% \def\x{\StrSubstitute{\x}{,}{\%2c}}%
% \def\x{\StrSubstitute{\x}{:}{\%3a}}%
% \def\x{\StrSubstitute{\x}{;}{\%3b}}%
% \edef\x{\StrSubstitute{\x}{=}{\%3d}}%
% \def\x{\StrSubstitute{\x}{?}{\%3f}}%
% \def\x{\StrSubstitute{\x}{@}{\%40}}%
% \def\x{\StrSubstitute{\x}{"}{\%22}}%
% \def\x{\StrSubstitute{\x}{<}{\%3c}}%
% \def\x{\StrSubstitute{\x}{>}{\%3e}}%
% \def\x{\StrSubstitute{\x}{\#}{\%23}}%
% \def\x{\StrSubstitute{\x}{\{}{\%7b}}%
% \def\x{\StrSubstitute{\x}{\}}{\%7d}}%
% \def\x{\StrSubstitute{\x}{|}{\%7c}}%
% \def\x{\StrSubstitute{\x}{\^}{\%5e}}%
% \def\x{\StrSubstitute{\x}{\~}{\%7e}}%
% \def\x{\StrSubstitute{\x}{[}{\%5b}}%
% \def\x{\StrSubstitute{\x}{]}{\%5d}}%
% \def\x{\StrSubstitute{\x}{\`}{\%60}}%
\x}}
\urlescape{abcd/efgh\%foo\#bar baz}
\end{document}
错误消息
然而,这是行不通的;我得到
! Use of \@xs@StrSubstitute@@ doesn't match its definition.
\kernel@ifnextchar ...rved@d =#1\def \reserved@a {
#2}\def \reserved@b {#3}\f...
l.35 \urlescape{abcd/efgh\%foo\#bar baz}
所以我想,TeX 书中有个奇怪的\edef
东西,让我们尝试一下:
\newcommand{\urlescape}[1]{{%
\def\x{\StrSubstitute{#1}{\%}{\%25}}%
\edef\x{\StrSubstitute{\x}{/}{\%2F}}%
...
但现在我得到了以下令我困惑的信息:
! Argument of \reserved@a has an extra }.
<inserted text>
\par
l.35 \urlescape{abcd/efgh\%foo\#bar baz}
我搜索了解决方案和问题,发现了几个提示,其中混合了复杂的魔法药水组合\noexpand
;\unexpanded
遗憾的是,我无法从这些解决方案中提取对我有用的咒语(我现在可能已经足够清楚地表明,对我而言,使用 TeX 更多的是一门艺术而不是一门科学)。
请不要犹豫地指出一个可以做到这一点的包 - URL 转义 - 但我认为如何在 LaTeX 中对字符串执行多次替换的问题是一个更普遍的兴趣,我相信我会经常需要这样的东西。
更新
解释:由于上面的列表太长,所以提出了这个问题;简单的答案是,我从http://perishablepress.com/stop-using-unsafe-characters-in-urls/。
在更具体的用例中,根据语义和环境,减少枚举是可能的,也可能是可取的。至于语义,无论您检索http://example.com/foo/bar#baz
或,它通常会有所不同http://example.com/foo%2Fbar%23baz
;在这样的 URL 中是否转义/
和/或#
本身是不可预测的,因此我从一个相当大的列表开始。
答案1
你是\x
根据自身来定义的,这不是一件好事。你宁愿将中间结果存储在临时宏中,这样xstring
就可以使用尾随的可选参数。
在进行第一次替换后存储参数,然后对存储的字符串进行操作。还有一个需要注意的扩展问题:最好的方法是压制 xstring
扩展并只手动执行一项:
\documentclass[a5paper]{article}
\usepackage{xstring}
\newcommand{\urlescape}[1]{{%
\noexpandarg % suppress expansions made by xstring
\StrSubstitute{#1}{\%}{\%25}[\x]% first step
\expandafter\StrSubstitute\expandafter{\x}{/}{\%2F}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\&}{\%26}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{ }{\%20}[\x]%
\expandafter\StrSubstitute\expandafter{\x}{\$}{\%24}[\x]%
\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}
一些语法糖可能会更好:
\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}