我想定义一个接受两个参数并生成网页链接的命令:
\newcommand{\urltocode}[2]{...}
但是问题是,当我使用 时\urltocode{foo}{bar}
,如果foo
包含一些非 ASCII 字符,pdflatex 会尖叫,foo
应该直接粘贴到 URL 中。实际上,foo
包含特殊符号(如#
http id)以及 unicode 符号。有没有办法定义\urltocode
绝对foo
不会重新解释?
举个例子,我想
\newcommand{\urltocode}[2]{\href{http://something.com/#1}{#2}}
其中#1
预计包含各种符号。我希望使用 ,\urltocode{foo}{bar}
就像 中一样自然foo
。
答案1
您遇到的问题似乎是由于 TeX 程序在从 .tex-input-file 读取内容时对 .tex-input 的标记/词法分析位与 TeX 程序在执行宏时和后期解析标记序列交织在一起造成的。
标记器将一段输入拆分为单元/单词。
词法分析器执行词汇分析 — 向单元/单词添加信息,提供有关该单元/单词是什么类型的信息。
解析器分析单元/单词的组合。
标记器将输入分为“单词”。词法分析器在“单词”级别工作,为“单词”添加附加信息。解析器在语法级别工作,分析单元/单词的组合。
.tex 输入文件的内容总是被读取并分割成单元(标记化),这些单元称为标记,其中添加了附加信息(词法分析器),例如所讨论的标记是控制序列标记还是显式字符标记,在这种情况下会添加有关该标记类别的信息。
在处理的后期阶段,当标记已经存在时,将解析标记序列。
您无法绕过 TeX 对来自 .tex 输入文件或在控制台中输入的 .tex 输入进行标记/词法分析。
但您可以(暂时)调整 TeX 的标记和词法分析装置,以便在执行 -macro 时解析事物时不会抱怨所创建的标记\href
。这就是 TeX 中的类别代码的目的:类别代码用于调整 TeX 的标记和词法分析装置将生成的标记。
一个常见的技巧是暂时切换到 verbatim-category-code-régime 来从 .tex-input-file 读取/标记/词法分析,然后将得到的标记集传递给\scantokens
。
verbatim-category-code-régime 的要点是:.tex 输入文件形成字符序列(不是字符标记 - 字符标记在 TeX 运行期间存在;文件存在于文件系统中)。如果 TeX 在 verbatim-category-code-régime 下读取/标记化/词法分析内容,则会产生字符标记,其未展开写入文件或终端会产生(或多或少)与读取/标记化/词法分析的文件中包含的相同字符集。
\scantokens
反过来,这就像将未展开的标记写入文件,然后根据执行时当前的类别代码机制(标记和词法分析规则集)读取、标记和词法分析该文件的内容\scantokens
。以这种方式生成并附加到标记流的标记将照常处理。
用户 202729 已经给出了一些例程的指示\DefineVerbatimToScantokens
:
\DefineVerbatimToScantokens{⟨control-word-token⟩}{⟨xparse-argument-specifiers⟩}{%
⟨verbatim-material to be passed to \scantokens⟩
}%
使用它你可以尝试这样的事情:
\documentclass{article}
\usepackage{hyperref}
%=== Code of \DefineVerbatimToScantokens ========================
% With older LaTeX-releases uncomment the following line:
%\usepackage{xparse}
\NewDocumentCommand\DefineVerbatimToScantokens{mm}{%
\begingroup
\catcode`\^^I=12\relax
\InnerDefineVerbatimToScantokens{#1}{#2}%
}%
\begingroup
\makeatletter
\def\InnerDefineVerbatimToScantokens#1#2{%
\endgroup
\NewDocumentCommand\InnerDefineVerbatimToScantokens{mm+v}{%
\endgroup\ReplaceHashloop{##3}{##1}{##2}%
}%
\newcommand\ReplaceHashloop[3]{%
\ifcat$\detokenize\expandafter{\Hashcheck##1#1}$%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{%
\NewDocumentCommand{##2}{##3}{%
\begingroup\newlinechar=\endlinechar
\scantokens{\endgroup##1#2}%
}%
}{%
\expandafter\ReplaceHashloop\expandafter{\Hashreplace##1}{##2}{##3}%
}%
}%
\@ifdefinable\Hashcheck{\long\def\Hashcheck##1#1{}}%
\@ifdefinable\Hashreplace{\long\def\Hashreplace##1#1{##1####}}%
}%
\catcode`\%=12\relax
\catcode`\#=12\relax
\InnerDefineVerbatimToScantokens{#}{%}%
%=== End of code of \DefineVerbatimToScantokens =================
% Be aware that indenting does matter within \DefineVerbatimToScantokens's
% <verbatim-material to be passed to \scantokens>-argument:
\DefineVerbatimToScantokens\urltocode{vv}{\href{http://something.com/#1}{#2}}%
\begin{document}
\urltocode{foo}{bar}
\end{document}
此短语bar
是指向 url 的链接https://something.com/foo
。
\scantokens
也许,你可以使用 hyperref 来代替所有这些逐字欺骗\hyperbaseurl
。
但过去我遇到了问题,因为当时\href
检测 url 类型/链接类型的例程似乎不知道何时考虑\hyperbaseurl
以及何时不考虑。例如,
\hyperbaseurl{https://something.com/}
\href{foo}{bar}
可能会产生一个指向不存在文件的链接,foo
而不是指向 url 的链接https://something.com/foo
。
参见。例如,\hyperbaseurl 适用于 .html,但不适用于 .pdf