防止 hyperref \href 在包含宏的目标 URL 中插入空格

防止 hyperref \href 在包含宏的目标 URL 中插入空格

我注意到我的 BibTeX 样式生成的一些链接不起作用,因为它们里面有空格。样式 (apsrev4-1) 使用类似以下内容将参考文献的期刊部分超链接到 doi.org 上的 DOI 解析器

\href {\doibase 10.1234/doi.handle}{Journal 12, 1234 (1984)}

但是,BibTeX 会对其输出进行自动换行,有时会在宏后面插入换行符\doibase。在这些情况下,生成的 URL 会在该宏的扩展后立即包含一个空格,例如https://doi.org/ 10.1234/doi.handle。我可以重现此行为:

\documentclass{article}

\usepackage{hyperref}

\newcommand{\base}[0]{http://www.example.com/}

\begin{document}
\href {\base test.html}{Link without space}

\href {\base
test.html}{Link with space}
\end{document}

如果我理解正确的话,这两次调用之间应该没有区别,因为宏后的所有空格都会被忽略。

我怎样才能使第二个版本的行为与第一个版本相似?我试图将其附加\ignorespaces到宏的定义中\base,但它所做的只是添加一个文字 (url-encoded) %5Cignorespaces

答案1

我不知道这对您是否有帮助,但是当 TeX 从 .tex-input-files 读取输入时,它会在输入行的每一端插入一个字符,该字符在 TeX 的内部字符编码方案中的代码点编号(对于传统 TeX 为 ASCII,对于基于 XeTeX 或 LuaTeX 的引擎为 unicode)等于整数参数的值\endlinechar

如果的值\endlinechar超出了字符可能的代码点数范围,则不插入任何字符。

通常的值为\endlinechar13(十进制),这意味着插入了一个返回字符,因为 13(十进制)是 ASCII 和 unicode 中返回字符的代码点编号。(TeX^^符号中的返回字符可以用 表示^^MM即字母表中的第 13 个字母。)

通常,返回字符的类别代码为 5。如果 TeX 在读取装置处于状态 S(跳过空格)时遇到 catcode-5 字符,则不会向该字符的标记流中插入任何标记。在对字符代码 32 和类别代码 10(空格)的显式空格标记、对控制字标记以及对控制空格进行标记之后,TeX 的读取装置切换到状态 S。\如果 TeX 在读取装置处于状态 M(行中间)时遇到 catcode-5 字符,则将字符代码 32 和类别代码 10(空格)的显式空格标记插入到该字符的标记流中。在对控制空格以外的字符标记或控制符号标记进行标记之后,TeX 的读取装置切换到状态 M。如果 TeX 在读取设备处于状态 N(新行)时遇到 catcode-5 字符,则控制字标记\par将插入到此字符的标记流中,无论其含义/定义\par如何。当开始对另一行进行标记时,TeX 的读取设备将切换到状态 N。

因此,您可以假设在\base(这是一个控制字标记)之后,阅读设备处于状态 S,因此由于 -thingie 而插入返回字符\endlinechar不会导致将任何标记插入到标记流中。

但是\href-command 有点特殊:\href在从 .tex 输入文件读取并开始标记 URL 参数之前,调用宏将返回字符的类别代码更改为 13(活动),并将活动返回字符定义为提供空格标记/类别代码为 10(空格)和字符代码为 32 的字符标记的宏。因此,\href.tex 输入文件中的换行符 URL 参数会将类别代码为 13(活动)的返回字符标记插入到标记流中。当时的活动返回字符标记被定义为扩展为空格标记的宏。

我不知道以下建议是否适合您的工作流程,但也许您可以分配\endlinechar一个超出字符可能的代码点数范围的值,例如值 -1。这样,TeX 就不会在换行符处插入任何字符。

\documentclass{article}

\usepackage{hyperref}
    
\newcommand{\base}[0]{http://www.example.com/}

\begin{document}
\href {\base test.html}{Link without space}

\href {\base
test.html}{Link with space}

%Probably something like this does the trick for you:

\begingroup
\endlinechar=-1\relax
\href{\base
test.html}{What's this?}
\endgroup


\end{document}

但是如果您可以搜索用于在各处插入的来源\begingroup\endlinechar=-1\relax..\endgroup,那么您也可以搜索用于删除 之后的换行符的来源\base

也许您可以定义\base一个宏来调用它,该宏会抓取一个非分隔参数,并(假设这是下一个标记)检查它是否是 active-return,并且仅在不是的情况下将其放回。但这有一些缺点:

  • 由于一切都必须按照宏扩展的方式进行,“前瞻”也必须通过宏参数来完成。因此前瞻不是在下一个标记上,而是在下一个宏参数上。如果后面有一个用花括号括起来的多标记参数\base,则这些花括号将被删除。如果在之后没有更多适合作为宏参数的标记\base,例如, \href{\base}{What's this?}那么您可能会收到一些 hyperref-release 错误消息。
  • \base仅会处理标记之后的换行符。

 

\documentclass{article}

\usepackage{hyperref}

\begingroup
\makeatletter
\catcode`\^^M=12\relax%
\def\activereturnfork#1{%
  \endgroup%
  \newcommand\activereturnfork[1]{%
    \forkactivereturn##1{}#1{##1}^^M^^M%
  }%
  \@ifdefinable\forkactivereturn{%
    \long\def\forkactivereturn##1#1##2##3^^M^^M{##2}%
  }%
}%
\catcode`\^^M=13\relax%
\activereturnfork{^^M}%

\newcommand{\base}[0]{http://www.example.com/\activereturnfork}

\begin{document}
\href {\base test.html}{Link without space}

\href {\base
test.html}{Link without space, too}

But:

% This will not be a link to http://www.example.com/{bracesremoved}.html
% but will be a link to  http://www.example.com/bracesremoved.html :
\href {\base {bracesremoved}.html}{Link with braces removed}
% But curly braces in any case are unsafe-characters and therefore in
% urls should be encoded with percent-encoding as %7B respective %7D .

% With current \hyper@normalize (hyperref 2018/11/30 v6.88e Hypertext links
% for LaTeX) this works by accident:
% \base/\activereturnfork takes \Hy@RemovePercentCr's \ifx for its argument
% and returns it:
\href {\base}{Attempts at creating this link may cause troubles when in future hyperref-releases internals are changed.}

\end{document}

可能最好的选择是修改 BibTeX 样式,以便不在非标准类别代码制度下标记的宏参数中进行换行。

相关内容