\string 和 \newcommand 如何工作?

\string 和 \newcommand 如何工作?

我尝试编写一个命令,使每个符号都可以链接到第一次出现的位置。考虑一个符号 A 和一个向量 B。定义一个命令,即 fun{'}=B' 和 fun{x}=B^{x}(其中 x=/=')。如果我想写 B^(A),那么我需要使用代码“fun{(A)}”。请注意,这个“A”使用代码“超链接”。但当\equal时不起作用\equal{(\hyperlink{x}{y})}{z}

这是我的问题的一个简单例子:

\documentclass{article}
\usepackage{hyperref}
\usepackage{ifthen}

\newcommand{\hyperaword}{(\hyperlink{1}{456})}

\begin{document}

\hypertarget{1}{3} % work
\hyperlink{1}{2} % work
\ifthenelse{\equal{\string\hyperaword}{456}}{123}{456} % work
\ifthenelse{\equal{\string (\hyperlink{1}{456})}{456}}{123}{456} % ERROR: Use of \hyper@link@ doesn't match its definition.
\end{document}

这个问题只在我使用“(\hyperlink{xx}{xx})”时才会出现。如果我使用“\hyperlink{xx}{xx}”而不是“( )”,那么就没问题了。

答案1

让我重写一下你的问题:

我有一个命令

\newcommand \f [1] { \ifthenelse { \equal {#1} {...} } ... }

这在大多数情况下都有效,但是当#1包含时\hyperlink,它会出错,而不仅仅是运行错误的分支。

回答:如包装中所述ifthen#1那样扩展获取要比较的字符串。

如果您想比较原始内容,请使用\detokenize

\string仅在有限的情况下起作用。

\newcommand \f [1] { \ifthenelse { \equal {\detokenize{#1}} {\detokenize{...}} } ... }

替代方法:使用 expl3 和\str_if_eq:nnTF\tl_if_eq:nnTF

答案2

\string在命令名称上返回名称作为字符串(catcode 12 的字符序列),因此\usepackage是单个标记,但\string\usepackage有 11 个标记\ u s e p a c k a g e

\ifthenelse equal扩展两个参数然后测试它们是否相等。

\equal{\string\hyperaword}{456}

测试 11 个 token \ hyperaword 是否等于三个 token 4 5 6,这永远不会成立,所以

\ifthenelse{\equal{\string\hyperaword}{456}}{123}{456}

总是456

在第二个测试中,\string(扩展为,(因为(已经是 catcode 12 的字符。但是,这\hyperlink是一个脆弱的命令,您不能在扩展上下文中使用。无论如何,它使用 pdftex 基元(如果您使用 pdftex)构建链接,因此,尤其是当被 包围时(),永远不会等于,456您可以通过使用来避免错误\protect\hyperlink,但随后测试是三个标记是否( \hyperlink )等于三个标记4 5 6,而这永远不会成立。

答案3

当 pdf 查看器显示 pdf 文件时,“超目标”基本上只是pdf 文件页面上的区域1 ,它有一个可以识别的名称。

当 pdf 查看器显示 pdf 文件时,“超链接”基本上只是 pdf 文件页面上的一个区域1,单击该区域可产生滚动效果2滚动到显示该 pdf 文件的窗口。

因此,宏\hypertarget是 LaTeX 编译器的一条指令,用于写入 pdf 文件指令,在查看 pdf 文件时,即当 LaTeX 编译器不再运行时,pdf 查看程序使用该指令为 pdf 文件中的区域命名。这种命名区域称为“目标”。这种区域的名称称为“目的地”。如果这种命名区域非常小,以至于可以将其视为 pdf 文件中的单个点,那么它也被称为“锚点” 。3

\hyperlink是让 LaTeX 编译器写入 pdf 文件指令的一条指令,在查看 pdf 文件时,即当 LaTeX 编译器不再运行时,pdf 查看程序使用该指令将 pdf 文件的某个区域与单击时将 pdf 文件的另一个(目标)区域滚动到显示 pdf 文件的窗口的指令连接起来。

在 TeX 运行期间,基于 pdfTeX 的引擎会跟踪命名区域的名称=目标/锚点,并在放置超链接但没有通过为 pdf 文件中的目标区域/锚点提供相应的名称来引入相应的目标的情况下,在 TeX 运行结束时引发错误消息。

没有 TeX 引擎使用\hypertarget/\hyperlink机制来跟踪 pdf 文件中那些指定的可滚动区域中出现的文本短语等。

概要:

\hyperlink在 LaTeX 运行期间不会返回任何有用信息。它仅触发对 pdf 文件的写入指令,这些指令由 pdf 查看程序在查看 pdf 文件时进行处理。也就是说,这些指令不是由 latex 编译器处理,而是由另一个程序(即 pdf 查看程序)处理。也就是说,这些指令是在 latex 编译器不再运行时,以及在 latex 编译器运行期间存在的所有数据都已不复存在时处理的。

代码中的表达式类似于
\ifthenelse{\equal{\string\hyperaword}{456}}{123}{456}
和,表示尝试以某种方式评估在运行 latex 编译器期间
\ifthenelse{\equal{\string (\hyperlink{1}{456})}
应用的“结果” 。\hyperlink

因此,尽管我不知道您到底想要实现什么,但我怀疑宏\hyperlink提供的标记/信息在 TeX 运行期间的进一步处理/检查是否对您有帮助。

如果我理解正确的话,现在的问题涉及对 TeX 宏的误解\hyperlink,这已经让理解这个问题变得困难。

请准确说明您希望实现的目标。也许我可以修改我的答案,添加一个代码示例来展示解决问题的方法。


1在分页符/列分隔符等情况下,超目标和超链接可能由多个区域组成,而不仅仅是一个区域。

2 “将 PDF 文件的另一个区域滚动到显示 PDF 文件的窗口”的含义取决于用于查看 PDF 文件的程序,因为遵循这些指令过程中的“操作”已实现到该程序中。不同的 PDF 查看程序的行为在边缘情况下会有所不同。

3 hyperref 包在许多情况下与锚点配合使用,假设单击相应链接时,锚点会滚动到显示 pdf 文件的窗口的左上角。在内部,hyperref 包指定锚点相对于包含单击链接时应在显示窗口中看到的文本/材料的框的参考点的位置。在水平模式下,TeX 本身将事物划分为框,据我所知,它是第一个水平框的参考点,其中包含单击链接时应在显示窗口中看到的文本/材料的部分。



以下示例提供了一个宏\LinkOrTarget{<destination name>}{<phrase>},其中第一个实例具有指定的⟨目的地名称⟩形成超目标,后续实例形成超链接。

如果出现命令\IntroduceHypertargetHere{<destination name>}{<phrase>},则该命令将形成超目标,而所有实例将\LinkOrTarget{<destination name>}{<phrase>}形成超链接。
如果出现命令\IntroduceHypertargetHere{<destination name>}{<phrase>},则需要多次 latex-run 直到所有内容都匹配。

因此:遵守终端和 .log 文件中有关重新运行 LaTeX 的必要性的信息和警告(在 LaTeX 运行之间不要删除辅助文件)。

不要放置\IntroduceHypertargetHere{<destination name>}{<phrase>}相同⟨目的地名称⟩不止一次。如果这样做,您将收到关于多重定义标签的警告,并且超目标将在第一次出现这些情况时创建。

\documentclass{article}
\usepackage{hyperref}
\usepackage{zref}

\makeatletter
\zref@newprop{DestinationExplicitlyPlaced}{}%
\newcommand\WrapHypertargetInHy@raisedlink[2]{%
  \Hy@raisedlink{\hypertarget{#1}{}}#2%
}%
\newcommand\IntroduceHypertargetHere[1]{%
  \zref@setcurrent{DestinationExplicitlyPlaced}{true}%
  \zref@labelbyprops{ExplicitDestination-#1}{DestinationExplicitlyPlaced}%
  \IntroduceHypertargetHereInternal{#1}%
}%
\newcommand\IntroduceHypertargetHereInternal[2]{%
  \@ifundefined{NameOfDestination_#1}{%
    \expandafter\gdef\csname NameOfDestination_#1\endcsname{}%
    \WrapHypertargetInHy@raisedlink
  }{\hyperlink}{#1}{#2}%
}%
\newcommand\LinkOrTarget[2]{%
  \zref@ifrefundefined{ExplicitDestination-#1}{\IntroduceHypertargetHereInternal}{%
    \zref@ifrefcontainsprop{ExplicitDestination-#1}{DestinationExplicitlyPlaced}%
                           {\hyperlink}{\IntroduceHypertargetHereInternal}%
  }%
  {#1}{#2}%
}%
\makeatother

\begin{document}

Dummy page
\newpage
Smme text \LinkOrTarget{destination name}{Phrase which either is in link area or is in target area}.
\newpage
Some text \LinkOrTarget{destination name}{Phrase which either is in link area or is in target area}.
\newpage
Some text \LinkOrTarget{destination name}{Phrase which either is in link area or is in target area}.
%Some text \IntroduceHypertargetHere{destination name}{Phrase which is in target area}.
\newpage
Some text \LinkOrTarget{destination name}{Phrase which either is in link area or is in target area}.
\newpage
Some text \LinkOrTarget{destination name}{Phrase which either is in link area or is in target area}.

\end{document}

相关内容