定义一个不解析输入的命令

定义一个不解析输入的命令

我想定义一个接受两个参数并生成网页链接的命令:

\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

相关内容