Can I define a command that takes an argument but does not eval the argument?
4 Answers
Ok, it seems that you mean the so called verbatim mode as "does not eval the argument". This is done in TeX by changing the category codes, short catcodes, of the special characters. This is done using \catcode<ASCII number of character>=<catcode><space or \relax>. The ASCII number of a character can be received by <character>`` or\``. Note that once TeX has read a character its catcode is fixed, so the changes must be made beforehand and should only be local!
The normal way to do is (1) change the catcodes in a group (2) call a second macro which reads the argument and closes the group (3) process the argument and read further arguments if required.
LaTeX helps here a little and provides \dospecials which holds all special characters preceded with \do, e.g. \do\\\do\%\do\& ..., so you only have to define \do to a macro which changes the catcode of these characters to something neutral, which is catcode 12 "other". The \@makeother macro does this for you! However, in this case the { and } must be changed back to there original catcodes 1 and 2 in order to be able to read the argument.
\documentclass{article}
\usepackage{hyperref}
\makeatletter
\def\hreffootnote{%
%\unskip
\begingroup
\let\do\@makeother
\dospecials
\catcode`\{=1\relax
\catcode`\}=2\relax
\href@footnote
}
\def\href@footnote#1{%
\endgroup
\href@@footnote{#1}%
}
\let\realhref\href
\def\href@@footnote#1#2{%
\footnote{\realhref{#1}{#2}}%
}
\begin{document}
Text\hreffootnote{http://foobar.com/~test/%^&*$_##/test}{there} after
Text \href{http://foobar.com/~test/%^&*$_##/test}{there} after
\let\href\hreffootnote
Text \href{http://foobar.com/~test/%^&*$_##/test}{there} after
Hello\href{http://www.google.com/#sclient=psy&hl=en&site=&source=hp&q=numbers&aq=f&aqi=&aql=&oq=&pbx=1&fp=d5033c56880e0199}{b} world.
\end{document}
Update 2011-07-27:
I now published a new version of newverbs which provides \collectverb and \Collectverb to collect verbatim arguments easily. See my answer to Changing href's to footnotes for an example for footnotes.
- 262,582
To answer the clarification of the question in the comments, this seems to work (though I'm no expert on the hyperref package so this might break something else, but if it does I'm sure that someone will stop by and say so).
\documentclass{article}
\usepackage{hyperref}
\let\oldhref=\href
\def\href#1#2{\footnote{\oldhref{#1}{#2}}}
\begin{document}
Hello\href{a}{b} world.
\end{document}
- 153,724
- 43
- 389
- 751
-
@dick: This approach of '
\letthe original to a saved name, then redefine the original' is standard TeX programming. TeX is a macro language, after all. – Joseph Wright Mar 06 '11 at 17:59 -
@Joseph: Yes, I should probably add that to my answer. I didn't want to post a long answer initially as I wasn't sure that this was what was wanted, and (as I said) I can't be sure that it doesn't break something else (I have the impression that the hyperref package is a bit touchy, but then I'm not sure that
\hrefis coming from\hyperrefeither). – Andrew Stacey Mar 06 '11 at 18:09 -
To clarify: I know that there is a command
\hrefin the hyperref package, but I don't know if there is another package that also defines it and that Dick is using instead of hyperref. (And\hyperref->hyperref) – Andrew Stacey Mar 06 '11 at 18:10 -
@Andrew thanks very much. I tried the earlier solutions and they work partially. The issue is more complex url's. The solutions seem to die when the url's include _ and & for example. – dick lipton Mar 07 '11 at 13:22
-
1@Andrew for example this breaks::: which is Wikipedia url \documentclass{article}
\usepackage{hyperref}
\let\oldhref=\href \def\href#1#2{\footnote{\oldhref{#1}{#2}}}
\begin{document}
Hello\href{http://www.google.com/#sclient=psy&hl=en&site=&source=hp&q=numbers&aq=f&aqi=&aql=&oq=&pbx=1&fp=d5033c56880e0199}{b} world.
\end{document}
– dick lipton Mar 07 '11 at 13:25 -
@dick: That URL breaks things anyway! It's nothing to do with the solution, just that
\footnote{\href{...}{...}}is not easy to deal with. I've asked a follow-up question to see if anyone else can shed some light on this: http://tex.stackexchange.com/q/12855/86 – Andrew Stacey Mar 07 '11 at 14:38
I posted this already on Dick's blog. I think there is an easier way to do what Dick wants to do (if I understand him correctly) by using the \url command provided by the hyperref package. In this case, you can just define the macro like this:
\newcommand\hreffootnote[2]{#2\footnote{\url{#1}}}`
Edit: This does not treat special characters in URLs correctly. But this seems to work (using hyperref):
\makeatletter
\newcommand\myhref@[2]{#2\footnote{\url@{#1}}}
\DeclareRobustCommand{\myhref}{\hyper@normalise\myhref@}
\makeatother
- 8,604
- 3
- 36
- 27
Just a point of clarification supporting Martin's answer, together with an attempt to put the behaviour in more of a programming language theory context and address some points in your weblog.
The problem here is the highly dynamic staged approach Tex takes to its input, described by Knuth in terms of an analogy with the digestive tract. Tex takes its input a character at a time as it evaluates and "looks" at them with its "eye" - what happens at this stage is that the characters get catcodes. Expansion is the next thing that happens to these tokens, when they are "chewed" by its "mouth". At the time a macro "takes" an argument, it assigns catcodes ahead enough that it has all of the argument: you can't avoid this, but you can change the catcodes before this happens. Martin's answer uses his package to change the catcodes to all be letters (I think), so that the URL can be treated as a normal string when the argument is read in.
If the set of valid Tex programs are those that terminate by executing the command behind the \bye primitive and the pure Tex programs are those that only read from one .tex file and do not write to it, then it is pretty much clear that the set of pure valid Tex programs is not recursive. To actually prove this, I think one would need to prove some things about Tex the program, because it does not have a formal specification. Then again. Knuth does have an implementation-independent notion of correctness for Tex, since has written cheques to bug hunters.
Knuth has never been one for the kind of discipline advocated by software engineers. Indeed, he weighed into the discussion following Dijkstra's "Goto considered harmful" paper with an opinion along the lines that goto is fine, even a good thing, if you know what you are doing (Knuth, 1974, "Structured Programming with go to Statements", Computing Surveys 6: 261–301). I guess the real problem with this style of programming is that it does not scale: two Knuths are not going to collaborate well.
Tex is not entirely eccentric as a programming language. It can be considered as a child of Strachey's GPM. But none of the other GPM-derived languages I've seen are routinely used with such a drastically dynamic approach to syntax.
- 21,014
- 5
- 65
- 121
-
I read somewhere that Knuth has stopped actually writing cheques to bug-hunters because lots of small-denomination cheques got flagged as possibly fraudulent behaviour by his bank... – Seamus Jul 27 '11 at 15:04
-
@Seamus: Really? I've changed the tense in that assertion. So what happens if you find a bug now? – Charles Stewart Jul 27 '11 at 15:57
-
I wish I could remember where I'd read this... From what I can remember, you still get a cheque, but for some reason, it isn't actually possible to cash it. (it isn't dated or it is invalid in some other way). I read this several years ago, so I could be wrong... – Seamus Jul 27 '11 at 16:08
\verb|some $%^& text|. However this doesn't work when\verbitself is an argument of another macro. – Martin Scharrer Mar 05 '11 at 16:03\newcommand{\commandname}[1]{definition}takes an argument but doesn't evaluate it if you don't use#1within thedefinitioncode. – Stefan Kottwitz Mar 05 '11 at 16:08\newcommand{\mycommand}[2]{\noexpand #1 #2}\mycommand{\textbf {gf}}\mycommand{\expandafter\textbf {gf}}#1is not expanded in a first time but it's possible with\expandafter– Alain Matthes Mar 05 '11 at 16:29\href{a}{b}to behave likeb\footnote{\url{a}}. See my answer below on how to do this. – Michael Ummels Mar 10 '11 at 13:22