13

My problem comes from pandoc and markdown, but it is not directly related with these tools, but instead with "customizing" the resulting pdf via some tex macro programming, so I think it is on topic.

I'm writting a document with markdown syntax and converting it to LaTeX (and html) via pandoc. This document contains hyperlinks to some web sites. When I write in markdown:

See [this web](http://tex.stackexchange.com/)

It produces in TeX:

See \href{http://tex.stackexchange.com/}{this web}

I want to implement a version of \href which, in addition to inserting a hyperlink in the pdf, it also makes a footnote containing the url, which is more useful for the printed version of the document. I did it as follows:

\let\oldhref=\href
\renewcommand{\href}[2]{\oldhref{#1}{#2}\footnote{\url{#1}}}

So far so good. It works as expected.

Now the problem is that pandoc also supports "internal references" to other sections in the document. If I have a section called Related work, pandoc automatically generates a internal anchor name related-work, so I can write in my markdown source:

# Related work
Blah blah

# Another section
See [section about related work](#related-work)

The above markdown is translated into:

\hyperdef{}{related-work}{\section{Related work}\label{related-work}}

Blah blah

\section{Another section}

See \href{\#related-work}{section about related work}.

Now my problems is that, with my redefinition of \href this internal reference also produces a footnote, which clearly unncesary. The footnote only shows the text #related-work, which is not useful for the reader, and in addition clicking ot the footnote text produces an error (while other footnotes which show urls work fine).

So, my question: how can I redefine \href in such a way that:

  1. If the first char of its first argument is # (or is it \#?), it behaves as the standard \href (no footnote)
  2. Else, it works as my redefinition (internal hyperlink plus footnote typeseting the destination url).
0

3 Answers 3

12

Here is an idea for a conditional

\iffirsttoken{<tokenlist>}{<token>}{<true>}{<false>}

using the kernel command \@car. You can use it in your redefinition of \href to test whether the first token is \#:

\documentclass{article}

\makeatletter
% this is found in latex.ltx:
% \def\@car#1#2\@nil{#1}
\def\iffirsttoken#1#2{%
  % define \@first@token to be the once expanded \@car of the first argument
  % i.e. the first token or balanced group:
  \expandafter\def\expandafter\@first@token\expandafter{\@car#1\@nil}%
  % test if the expansion of \@first@token is the same as #2:
  \expandafter\ifx\@first@token#2\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

\usepackage{hyperref}

\let\oldhref\href
\renewcommand{\href}[2]{%
  \oldhref{#1}{#2}%
  \iffirsttoken{#1}{\#}{}{\footnote{\url{#1}}}%
}

\begin{document}

\hyperdef{}{related-work}{\section{Related work}\label{related-work}}

\iffirsttoken{foo}{f}{true}{false}% true

\iffirsttoken{\#related-work}{\#}{true}{false}% true

\iffirsttoken{this web}{\#}{true}{false}% false

\href{http://tex.stackexchange.com}{this web}

\href{\#related-work}{section about related work}

\end{document}

enter image description here

1
  • @JLDiaz Note that it will fail in cases like \iffirsttoken{{ffoo}bar}{f}{true}{false}% => ooftrue, though.
    – cgnieder
    Commented Feb 27, 2013 at 20:28
3

If you are looking to strip \# from the first position of a string, it can be done simply with this command

\newcommand\strippound[1]{\expandafter\ifx\expandafter\##1\else#1\fi}

Now stripping a # is a different beast, because it is a special character in TeX


After a day of reflection, I had an idea on how to strip an actual # sign (not a \# sign, mind you) from the first character of a string. This is a significant result, I think, given how difficult is is for TeX to operate on the # character. In the end, the answer was amazingly simple. Here it is:

\documentclass{article}

\catcode `#=11
\edef\lb{#}
\catcode `#=6
\newcommand\strippound[1]{\if\lb#1\else#1\fi}

\begin{document}
\noindent
\strippound{#This string began with a pound sign}\\    \strippound{This string did not begin with a pound sign}
\end{document}

enter image description here

4
  • Interesting! Athough this is not related to my question (I wanted only to execute different code depending on the first char being \#) the idea of changing the catcode and defining a macro with the "dangerous character" can be useful in other problems.
    – JLDiaz
    Commented Mar 1, 2013 at 13:38
  • 3
    Btw, this effect can also be ahcieved without catcode changes: \newcommand\strippound[1]{\if###1\else#1\fi} Commented Mar 1, 2013 at 15:18
  • @SašoŽivanović Fascinating. Could you explain what is going on inside LaTeX with the ###1 syntax? Commented Mar 1, 2013 at 15:39
  • @SašoŽivanović I found the answer to my previous comment at tex.stackexchange.com/questions/42463/…. Thanks for the tip. Commented Mar 1, 2013 at 23:42
0

I wasn't sure whether to edit my prior answer or add this new one. But this seemed unique enough addition to the discussion to warrant a new post. I will delete it if the group thinks it doesn't below here.

In my prior answer, I discovered how to remove a catcode 6 # from the leading position of a string. That watershed opened up a whole bunch of new ways in which catcode 6 # signs can be manipulated from input streams.

In this following bit of code, in addition to getting rid of the leading pound (which I now call \leadingpound, I also generate routines to convert all catcode 6 # signs into \# signs, and a routine to strip all catcode 6 pound signs from the input stream

As JLDiaz noted in the last answer, the technique opens up new ways in which the "dangerous character" can be processed. I hope you agree this is a start.

\documentclass{article}
\usepackage{ifnextok}

\catcode `#=11
\edef\lb{#}
\catcode `#=6
\newcommand\leadingpound[1]{\if\lb#1\else#1\fi}

\makeatletter
\def\@stringend{$}
\def\convertpounds#1{\scan@Block#1\@stringend}
\def\scan@Block{\IfNextToken\@stringend{\@gobble}%
  {\IfNextToken\@sptoken{ \conv@rt{\scan@Block}}%
  {\conv@rt{\scan@Block}}}}

\def\conv@rt#1#2{\if\lb#2\#\else#2\fi#1}

\def\strippounds#1{\process@Block#1\@stringend}
\def\process@Block{\IfNextToken\@stringend{\@gobble}%
  {\IfNextToken\@sptoken{ \bl@t{\process@Block}}%
  {\bl@t{\process@Block}}}}

\def\bl@t#1#2{\if\lb#2\else#2\fi#1}
\makeatother

\begin{document}
\noindent
The following commands work on raw (catcode 6) pound signs
(not backslash-pound symbols).
\vspace{1ex}\\
Started as \convertpounds{#ABC}.  After leadingpound:
  \leadingpound{#ABC}
  $\leftarrow$ No \# may follow lead \#\\
Started as \convertpounds{#A#BC#}.  After convertpounds:
  \convertpounds{#A#BC#}
  $\leftarrow$ These are $\backslash$\#\\
Started as \convertpounds{#A#BC#}.  After strippounds:
  \strippounds{#A#BC#}
\end{document}

enter image description here

You must log in to answer this question.

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