GeneralProblem creating a macro that accepts arguments containing a hash/sharp symbol ("#")

LaTeX specific issues not fitting into one of the other forums of this category.
Post Reply
cypherpunks
Posts: 15
Joined: Sat Dec 10, 2016 12:26 pm

Problem creating a macro that accepts arguments containing a hash/sharp symbol ("#")

Post by cypherpunks »

This is a mostly working example of how to put URLs in a footnote and hyperlink them in the body of a document:

Code: Select all

\documentclass[pdftex]{scrartcl}

\usepackage[driver=pdftex,margin=25mm]{geometry}
\usepackage[hyperfootnotes=false]{hyperref} % hotlinking footnotes disabled
\usepackage{xstring}  % used for \StrSubstitute in the def of \footnoteurl
\usepackage{lipsum} 

\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{#1}}}
%\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{\string{#1}}}}
%\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{\detokenize{#1}}}}
%\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\detokenize{\nolinkurl{#1}}}}
%\newcommand{\footnoteurl}[2]{\StrSubstitute{#1}{\#}{\#}[\cleanurl]\href{#1}{#2}\footnote{\nolinkurl{\cleanurl}}}
%\newcommand{\footnoteurl}[2]{\expandafter\StrSubstitute{#1}{\#}{\#}[\cleanurl]\href{#1}{#2}\footnote{\nolinkurl{\cleanurl}}}
%\newcommand{\footnoteurl}[2]{\noexpand\StrSubstitute{#1}{\#}{\#}[\cleanurl]\href{#1}{#2}\footnote{\nolinkurl{\cleanurl}}}

%\newcommand{\urlescape}[1]{{%
%  \noexpandarg % suppress expansions made by xstring
%  \StrSubstitute{#1}{\#}{\#}[\x]% first step
%  \expandafter\StrSubstitute\expandafter{\x}{_}{\textunderscore }[\x]%
%  \x}}
%\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{#1}}} % must escape hashes; e.g. "\#"

\begin{document}
\lipsum[1]

\vspace{1em}
Yada yada \footnoteurl%
{https://www.sourcewatch.org/index.php?title=ALEC_Civil_Justice_Task_Force\#Politicians}{%
ALEC financing} Yada yada
\vspace{1em}

\lipsum[1]
\end{document}
Notice that the “#” in the URL had to be escaped with a backslash. This should not be necessary. Note that the \href and \url commands themselves do not require this, so it should be possible to write a macro that also does not require escaping the “#”. Notice all the commented out code. These are all failing attempts to remedy the problem.

Recommended reading 2024:

LaTeXguide.org • LaTeX-Cookbook.net • TikZ.org

NEW: TikZ book now 40% off at Amazon.com for a short time.

User avatar
Ijon Tichy
Posts: 640
Joined: Mon Dec 24, 2018 10:12 am

Problem creating a macro that accepts arguments containing a hash/sharp symbol ("#")

Post by Ijon Tichy »

This cannot be done using \newcommand{\foo}[1]. You have to first change \catcode (not only of the hash but of several other characters too) and then read the argument and process it. Last but nut least you have to restore the original catcodes. This is fare away from being trivial. A large portion of the (well documented) code of \Url, \Url@y and \Url@x in package url is for reading the argument verbatim and convert it so something that can be handled by itself and by hyperref. Same for hyperref's \href. Here hyperref uses \hyper@normalise to open a group and change catcodes before reading the verbatim argument.

If it would be easy to do something like this, it would be documented in the user manuals instead of recommending to use \urldef. If you really want to implement such a command you have to enter a much lower level.

In the following example I use a temporary redefinition of an internal hyperref command to get the verbatim URL and use it as an argument of another command. However, I do not recommend to use such hacks! They can fail under several circumstances, e.g., if a driver or hyperref itself changes the use of the internal command or the internal command itself!

Code: Select all

\documentclass{scrartcl}% NOTE: Nobody needs option pdftex. Remove it!

\usepackage[margin=25mm]{geometry}% NOTE: geometry does not need option driver=pdftex. Remove it!
\usepackage[hyperfootnotes=false]{hyperref} % hotlinking footnotes disabled
\usepackage{xstring}  % used for \StrSubstitute in the def of \footnoteurl
\usepackage{lipsum} 

\makeatletter
% NOTE: The following is an ugly hack, that temporary redefines an internal
%       command of hyperref to process the verbatim URL. There is not warranty
%       and no support for this code or documents using this code!
\newcommand*{\footnoteurl}{%
  \global\let\original@hyper@@link\hyper@@link
  \let\hyper@@link\onetime@special@hyper@@link% Ugly hack
  \href
}
\newcommand*{\onetime@special@hyper@@link}[3]{%
  \global\let\hyper@@link\original@hyper@@link% Ugly hack
  \hyper@@link{#1}{#2}{#3}%
  \IfArgIsEmpty{#2}{\footnote{\nolinkurl{#1}}}{\footnote{\nolinkurl{#1\##2}}}%
}
\makeatother

\begin{document}
\lipsum[1]

\vspace{1em}
Yada yada \footnoteurl%
{https://www.sourcewatch.org/index.php?title=ALEC_Civil_Justice_Task_Force\#Politicians}{%
ALEC financing} Yada yada\footnoteurl%
{https://www.sourcewatch.org/index.php?title=ALEC_Civil_Justice_Task_Force}{%
ALEC financing}
\vspace{1em}

\lipsum[1]
\end{document}
Sorry, but I can no longer participate here as the administrator is trampling on my wishes on one of his other platforms. :cry:
cypherpunks
Posts: 15
Joined: Sat Dec 10, 2016 12:26 pm

Problem creating a macro that accepts arguments containing a hash/sharp symbol ("#")

Post by cypherpunks »

Thanks for the detailed reply. That code is well over my head. I'll use it in one document so I have a copy of it to refer back to, but I guess I'll use this simpler version on a regular basis:

Code: Select all

\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\tiny\nolinkurl{#1}}}
..which means I'll have to escape the hashes ("\#"). If I write a doc with a lot of hash-containing URLs, I'll probably bring out your hack.

Thanks!
Post Reply