9

How can I store a URL in a macro if the URL has a # and/or a % in it? The MWE below works fine for the first two, but not the third one.

enter image description here

Notes:

  • One solution is to replace the # with \string# and the % with \%, but wodering if there is an easier way.

  • I realize that this may mess up the syntax highliting, but the \csdef{} section shown here will be in a separte .def file that will be be \input{}, so not an issue.

Reference:

Code

\documentclass{article}
\usepackage{etoolbox}
\usepackage{hyperref}
\usepackage{tikz}

\csdef{url Title 1}{The Google}
\csdef{url Link 1}{http://www.google.com}

\csdef{url Title 2}{TeX.SE}
\csdef{url Link 2}{http://tex.stackexchange.com}

%\csdef{url Title 3}{Algebra and Trigonometry:~History of Trigonometry}
%\csdef{url Link 3}{https://books.google.com/books?id=4tFFDwAAQBAJ&pg=PT233&dq=history+of+trigonometry&hl=en&newbks=1&newbks_redir=0&sa=X&ved=2ahUKEwjIzcj0-tnqAhXwFjQIHZ6XDLUQ6AEwAnoECAQQAg#v=onepage&q&f=false}

\def\MaxNUmberOfURLs{5}
\newcommand{\DisplayURLs}{%
    \textbf{List of URLs}
    \foreach \xCount in {1,...,\MaxNUmberOfURLs} {%
        \ifcsdef{url Title \xCount}{%
            \par\xCount:
            \href{\csuse{url Link \xCount}}{\csuse{url Title \xCount}}
        }{}%
    }%
}

\begin{document}
\DisplayURLs
\end{document}
3
  • \csedef{url Link 3}{\detokenize{https://books.google.com/books?id=4tFFDwAAQBAJ&pg=PT233&dq=history+of+trigonometry&hl=en&newbks=1&newbks_redir=0&sa=X&ved=2ahUKEwjIzcj0-tnqAhXwFjQIHZ6XDLUQ6AEwAnoECAQQAg#v=onepage&q&f=false}} should work. edit Hrmpf: It works in the MWE, but breaks with %.
    – moewe
    Commented Jul 19, 2020 at 18:49
  • 1
    You asked, "How can I store a URL in a macro if the URL has a # and/or a % in it?" Isn't this precisely what the \urldef macro of the url package is supposed to do? E.g., \urldef{\myURL}\url{https://books.google.com/books?id=4tFFDwAAQBAJ&pg=PT233&dq=history+of+trigonometry&hl=en&newbks=1&newbks_redir=0&sa=X&ved=2ahUKEwjIzcj0-tnqAhXwFjQIHZ6XDLUQ6AEwAnoECAQQAg#v=onepage&q&f=false}
    – Mico
    Commented Jul 19, 2020 at 19:54
  • 1
    @Mico: Did not know about that. You should post an asnwer as that might be a better alternative for some. For me, the \csdefurl defined in moewe's answer works great. Commented Jul 19, 2020 at 20:53

2 Answers 2

5

hyperref's \hyper@normalise comes in extremely handy here. It can be used to sanitise the argument of a macro and allow it to accept special characters without escaping. (I think I first learned about \hyper@normalise from Michael Ummels' answer to Getting those %#!^& signs in the footnote!)

Just use it to define a new macro like \newcommand*{\csdefurl}[1]{\hyper@normalise{\csdef{#1}}}. (Note that the argument that is going to be "normalised" is not explicitly part of the definition. \newcommand*{\csdefurl}[2]{\hyper@normalise{\csdef{#1}}{#2}} would not work because then the argument is read with the unnormalised catcode setup.)

\documentclass{article}
\usepackage{etoolbox}
\usepackage{hyperref}
\usepackage{tikz}

\makeatletter
\newcommand*{\csdefurl}[1]{\hyper@normalise{\csdef{#1}}}
\makeatother

\csdef{url Title 1}{The Google}
\csdefurl{url Link 1}{http://www.google.com}

\csdef{url Title 2}{TeX.SE}
\csdefurl{url Link 2}{http://tex.stackexchange.com}

\csdef{url Title 3}{Algebra and Trigonometry:~History of Trigonometry}
\csdefurl{url Link 3}{https://example.com/~test/a%20and%20b.html#anchor}

\def\MaxNUmberOfURLs{5}
\newcommand{\DisplayURLs}{%
    \textbf{List of URLs}
    \foreach \xCount in {1,...,\MaxNUmberOfURLs} {%
        \ifcsdef{url Title \xCount}{%
            \par\xCount:
            \href{\csuse{url Link \xCount}}{\csuse{url Title \xCount}}
        }{}%
    }%
}

\begin{document}
\DisplayURLs
\end{document}

Screenshot of the output. The third item reads "Algebra and Trigonometry: History of Trigonometry" and the little pop-up the PDF viewer shows on hover displays "https://example.com/~test/a%20and%20b.html#anchor"


Some more testing reveals that

\makeatletter
\newcommand*{\csdefurl@i}{}
\newrobustcmd*{\csdefurl}[1]{%
  \def\csdefurl@i{\csdef{#1}}%
  \hyper@normalise\csdefurl@i}
\makeatother

might be safer.

Compare this definition to the one above in

\documentclass{article}
\usepackage{etoolbox}
\usepackage{hyperref}
\usepackage{tikz}

\makeatletter
\newcommand*{\csdefurl@i}{}
\newrobustcmd*{\csdefurl}[1]{%
  \def\csdefurl@i{\csdef{#1}}%
  \hyper@normalise\csdefurl@i}
\makeatother

\csdef{ürl Title 1}{The Google}
\csdefurl{ürl Link 1}{http://www.google.com}

\csdef{ürl Title 2}{TeX.SE}
\csdefurl{ürl Link 2}{http://tex.stackexchange.com}

\csdef{ürl Title 3}{Algebra and Trigonometry:~History of Trigonometry}
\csdefurl{ürl Link 3}{https://example.com/~test/a%20and%20b.html#anchor}

\def\MaxNUmberOfURLs{5}
\newcommand{\DisplayURLs}{%
    \textbf{List of URLs}
    \foreach \xCount in {1,...,\MaxNUmberOfURLs} {%
        \ifcsdef{ürl Title \xCount}{%
            \par\xCount:
            \href{\csuse{ürl Link \xCount}}{\csuse{ürl Title \xCount}}
        }{}%
    }%
}

\begin{document}
\DisplayURLs
\end{document}

where we have the non-ASCII ürl instead of url.

7

You asked,

"How can I store a URL in a macro if the URL has a # and/or a % in it?"

The \urldef directive of the url package lets you create precisely such macros. E.g.,

\urldef{\myURL}\url{https://books.google.com/books?id=4tFFDwAAQBAJ&pg=PT233&dq=history+of+trigonometry&hl=en&newbks=1&newbks_redir=0&sa=X&ved=2ahUKEwjIzcj0-tnqAhXwFjQIHZ6XDLUQ6AEwAnoECAQQAg#v=onepage&q&f=false}

Note the syntax: \urldef{<macroname>}\url{<URLstring>}. Observe taht \url{<URLstring>} must not be enclosed in curly braces.

\myUrl may be used in the argument of \footnote directives.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .