我尝试编写一个命令,使每个符号都可以链接到第一次出现的位置。考虑一个符号 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}