LaTeX forum ⇒ 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.
cypherpunks
Posts: 4
Joined: Sat Dec 10, 2016 12:26 pm

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

Postby cypherpunks » Wed Jun 17, 2020 8:58 pm

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] [Expand/Collapse] [Download] ({untitled.tex})
  1. \documentclass[pdftex]{scrartcl}
  2.  
  3. \usepackage[driver=pdftex,margin=25mm]{geometry}
  4. \usepackage[hyperfootnotes=false]{hyperref} % hotlinking footnotes disabled
  5. \usepackage{xstring} % used for \StrSubstitute in the def of \footnoteurl
  6. \usepackage{lipsum}
  7.  
  8. \newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{#1}}}
  9. %\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{\string{#1}}}}
  10. %\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{\detokenize{#1}}}}
  11. %\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\detokenize{\nolinkurl{#1}}}}
  12. %\newcommand{\footnoteurl}[2]{\StrSubstitute{#1}{\#}{\#}[\cleanurl]\href{#1}{#2}\footnote{\nolinkurl{\cleanurl}}}
  13. %\newcommand{\footnoteurl}[2]{\expandafter\StrSubstitute{#1}{\#}{\#}[\cleanurl]\href{#1}{#2}\footnote{\nolinkurl{\cleanurl}}}
  14. %\newcommand{\footnoteurl}[2]{\noexpand\StrSubstitute{#1}{\#}{\#}[\cleanurl]\href{#1}{#2}\footnote{\nolinkurl{\cleanurl}}}
  15.  
  16. %\newcommand{\urlescape}[1]{{%
  17. % \noexpandarg % suppress expansions made by xstring
  18. % \StrSubstitute{#1}{\#}{\#}[\x]% first step
  19. % \expandafter\StrSubstitute\expandafter{\x}{_}{\textunderscore }[\x]%
  20. % \x}}
  21. %\newcommand{\footnoteurl}[2]{\href{#1}{#2}\footnote{\nolinkurl{#1}}} % must escape hashes; e.g. "\#"
  22.  
  23. \begin{document}
  24. \lipsum[1]
  25.  
  26. \vspace{1em}
  27. Yada yada \footnoteurl%
  28. {https://www.sourcewatch.org/index.php?title=ALEC_Civil_Justice_Task_Force\#Politicians}{%
  29. ALEC financing} Yada yada
  30. \vspace{1em}
  31.  
  32. \lipsum[1]
  33. \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.

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

Postby Ijon Tichy » Thu Jun 18, 2020 8:08 am

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] [Expand/Collapse] [Download] ({untitled.tex})
  1. \documentclass{scrartcl}% NOTE: Nobody needs option pdftex. Remove it!
  2.  
  3. \usepackage[margin=25mm]{geometry}% NOTE: geometry does not need option driver=pdftex. Remove it!
  4. \usepackage[hyperfootnotes=false]{hyperref} % hotlinking footnotes disabled
  5. \usepackage{xstring} % used for \StrSubstitute in the def of \footnoteurl
  6. \usepackage{lipsum}
  7.  
  8. \makeatletter
  9. % NOTE: The following is an ugly hack, that temporary redefines an internal
  10. % command of hyperref to process the verbatim URL. There is not warranty
  11. % and no support for this code or documents using this code!
  12. \newcommand*{\footnoteurl}{%
  13. \global\let\original@hyper@@link\hyper@@link
  14. \let\hyper@@link\onetime@special@hyper@@link% Ugly hack
  15. \href
  16. }
  17. \newcommand*{\onetime@special@hyper@@link}[3]{%
  18. \global\let\hyper@@link\original@hyper@@link% Ugly hack
  19. \hyper@@link{#1}{#2}{#3}%
  20. \IfArgIsEmpty{#2}{\footnote{\nolinkurl{#1}}}{\footnote{\nolinkurl{#1\##2}}}%
  21. }
  22. \makeatother
  23.  
  24. \begin{document}
  25. \lipsum[1]
  26.  
  27. \vspace{1em}
  28. Yada yada \footnoteurl%
  29. {https://www.sourcewatch.org/index.php?title=ALEC_Civil_Justice_Task_Force\#Politicians}{%
  30. ALEC financing} Yada yada\footnoteurl%
  31. {https://www.sourcewatch.org/index.php?title=ALEC_Civil_Justice_Task_Force}{%
  32. ALEC financing}
  33. \vspace{1em}
  34.  
  35. \lipsum[1]
  36. \end{document}

cypherpunks
Posts: 4
Joined: Sat Dec 10, 2016 12:26 pm

Postby cypherpunks » Thu Jun 18, 2020 2:21 pm

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] [Expand/Collapse] [Download] ({untitled.tex})
  1. \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!


Return to “General”

Who is online

Users browsing this forum: No registered users and 6 guests