我的问题来自 pandoc 和 markdown,但它与这些工具没有直接关系,而是通过一些 tex 宏编程“定制”生成的 pdf,所以我认为它是主题。
我正在用 markdown 语法编写文档,并通过 pandoc 将其转换为 LaTeX(和 html)。此文档包含一些网站的超链接。当我用 markdown 编写时:
See [this web](http://tex.stackexchange.com/)
它在 TeX 中生成:
See \href{http://tex.stackexchange.com/}{this web}
我想实现一个版本\href
,除了在pdf中插入超链接外,它还会制作一个包含url的脚注,这对文档的打印版本更有用。我这样做了如下:
\let\oldhref=\href
\renewcommand{\href}[2]{\oldhref{#1}{#2}\footnote{\url{#1}}}
到目前为止一切顺利。它按预期运行。
现在的问题是,pandoc 还支持对文档中其他部分的“内部引用”。如果我有一个名为的部分Related work
,pandoc 会自动生成一个内部锚点名称related-work
,这样我就可以在我的 markdown 源中写入:
# Related work
Blah blah
# Another section
See [section about related work](#related-work)
上述 markdown 翻译为:
\hyperdef{}{related-work}{\section{Related work}\label{related-work}}
Blah blah
\section{Another section}
See \href{\#related-work}{section about related work}.
现在我的问题是,我重新定义\href
这个内部引用时还会产生一个脚注,这显然是不必要的。脚注只显示文本#related-work
,这对读者来说毫无用处,此外单击脚注文本会产生错误(而显示网址的其他脚注则工作正常)。
所以,我的问题是:我该如何重新定义\href
:
- 如果其第一个参数的第一个字符是
#
(或者是\#
?),则它表现为标准\href
(无脚注) - 否则,它就像我的重新定义一样工作(内部超链接加上脚注排版目标网址)。
答案1
以下是一个条件句的想法
\iffirsttoken{<tokenlist>}{<token>}{<true>}{<false>}
使用 kernel 命令\@car
。您可以在重新定义中使用它来\href
测试第一个标记是否是\#
:
\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}
答案2
如果你想要从字符串的第一个位置删除 \#,则可以使用此命令轻松完成
\newcommand\strippound[1]{\expandafter\ifx\expandafter\##1\else#1\fi}
现在去掉 # 就完全是另一回事了,因为它是 TeX 中的特殊字符
经过一天的思考,我想到了一个办法,如何从字符串的第一个字符中去掉真正的 # 符号(注意,不是 \# 符号)。我认为,这是一个有意义的结果,因为 TeX 操作 # 字符非常困难。最后,答案出奇地简单。答案如下:
\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}
答案3
我不确定是否要编辑我之前的回答或添加这个新回答。但这似乎足够独特,值得在讨论中添加一个新帖子。如果小组认为下面的帖子不合适,我会删除它。
在我之前的回答中,我发现了如何从字符串的开头位置删除 catcode 6 #。这一分水岭开辟了从输入流中操纵 catcode 6 # 符号的一系列新方法。
在以下这段代码中,除了删除前导磅号(我现在称之为 \leadingpound)之外,我还生成了将所有 catcode 6 # 符号转换为 \# 符号的例程,以及从输入流中删除所有 catcode 6 磅号的例程
正如 JLDiaz 在上一个回答中指出的那样,该技术开辟了处理“危险人物”的新方法。我希望您同意这是一个开始。
\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}