有一次我\cprotect
在我的章节标题周围添加了内容(我需要这样做,因为其中一些标题中可能包含数学)。现在,当我打开 PDF 文件时,所有书签都丢失了,取而代之的是,我看到cpt
每个书签上都有内容,但章节和小节名称没有显示。在使用之前,我得到了一个答案\usepackage[bookmarks=false]{hyperref}
,但当时我不知道这是什么意思。现在我注意到它会导致 PDF 书籍标记丢失,所以我不能使用这样的解决方案。
平均能量损失
\documentclass[12pt]{book}
\usepackage{cprotect}
\usepackage{hyperref}
\begin{document}
\chapter{A}
\cprotect\section{B}
\cprotect\subsection{C}
stuff
\cprotect\subsection{D}
stuff
\end{document}
使用编译lualatex
.....
Chapter 1.
(./foo3-1.cpt)
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
(hyperref) removing `\@ifnextchar' on input line 8.
(./foo3-2.cpt)
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
(hyperref) removing `\@ifnextchar' on input line 9.
(./foo3-3.cpt)
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
(hyperref) removing `\@ifnextchar' on input line 12.
PDF 文件书签如下所示(Adobe PDF 阅读器)
删除cprotect
后即可正常工作:
\documentclass[12pt]{book}
\usepackage{hyperref}
\begin{document}
\chapter{A}
\section{B}
\subsection{C}
stuff
\subsection{D}
stuff
\end{document}
给出
我想使用cprotect
,但又不想丢失 PDF 书签。有什么办法吗?
順利2020 年 Linux 版
更新以回答评论
请编辑您的帖子以给出导致悲痛的 \section 命令的实际示例。
下面是一个在 LuaTeX 上失败的示例,除非我使用\cprotect
,当我使用 时\cprotect
书签会丢失。发生这种情况是因为我使用了\usepackage{Baskervaldx}
我喜欢的字体
\documentclass[12pt]{book}
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\setmathfont{Asana Math}
\usepackage{Baskervaldx}
\usepackage{amsmath}
\usepackage{hyperref}
\begin{document}
\tableofcontents
\chapter{A}
\section{$\cos\left( A+B\right) $ and $\sin\left( A+B\right) $}%
\subsection{C}
stuff
\subsection{D}
stuff
\end{document}
使用 LuaLaTeX 编译可得
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
(hyperref) removing `math shift' on input line 15.
! Improper alphabetic constant.
<to be read again>
\math@bgroup
l.15 \section{$\cos\left( A+B\right) $ and $\sin\left( A+B\right) $}
%
?
但如果我使用cprotect
它,它会编译时没有错误,但现在没有书签
\documentclass[12pt]{book}
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\setmathfont{Asana Math}
\usepackage{Baskervaldx}
\usepackage{amsmath}
\usepackage{hyperref}
\usepackage{cprotect}
\begin{document}
\tableofcontents
\chapter{A}
\cprotect\section{$\cos\left( A+B\right) $ and $\sin\left( A+B\right) $}%
\subsection{C}
stuff
\subsection{D}
stuff
\end{document}
给出
我有很多这样的例子。下面是另一个
\section{ this is $\zeta$ }%
给出
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
(hyperref) removing `math shift' on input line 15.
! Improper alphabetic constant.
<to be read again>
\mitzeta
l.15 \section{ this is $\zeta$ }
%
?
请注意,这些都失败了,因为我正在使用字体
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\setmathfont{Asana Math}
\usepackage{Baskervaldx}
我当然可以不使用上面的字体,这样它就可以编译成功,书签也会保留在那里(但没有 Math,这对我来说没问题)。所以也许我必须这样做并使用上面的字体,我喜欢它,但保留书签更重要。所以如果没有其他解决方案,这是一个选择。
是否可以告诉 hyperref,如果它找到可以放入书签的内容,则只能对该部分进行替换.cpt
,而不能对所有内容进行替换?
问题是我预处理了整个 LaTeX 文件,并在每个部分和小节周围添加了 \cprotect,以防其中有数学内容。所以现在所有书签都丢失了。
我无法逐一进行此操作,因为我有数万个这样的条目。
记录发现的错误及解决方法
这太小了,无法在评论中写下,所以我在这里添加它。
由于包的顺序错误而产生的错误。这与 luacode 无关。
这失败了
% !TEX TS-program = lualatex
\documentclass{book}
\usepackage{amsmath,mleftright}
\usepackage{unicode-math}
\usepackage{Baskervaldx}
\setmathfont{Asana Math}[Scale=MatchLowercase]
\usepackage{xcolor}
\usepackage[colorlinks,allcolors=blue,linktocpage]{hyperref}
\begin{document}
\section{Solve numerically the ODE $u''''+u=f$ using point collocation method}
test
\end{document}
使用 LuaLaTeX 编译后
t) (./foo3.out)
! Undefined control sequence.
\g__um_prime_font_cmd_tl ->\l__um_font
l.14 \section{Solve numerically the ODE $u''''+u=f$ using point collocation method}
?
解决方法是\usepackage{Baskervaldx}
后 \setmathfont{Asana Math}
,所以顺序变成
\usepackage{amsmath,mleftright}
\usepackage{unicode-math}
\setmathfont{Asana Math}[Scale=MatchLowercase]
\usepackage{Baskervaldx}
\usepackage{xcolor}
\usepackage[colorlinks,allcolors=blue,linktocpage]{hyperref}
现在编译成功了。这与本节中的数学无关。以下是示例:
% !TEX TS-program = lualatex
\documentclass{book}
\usepackage{amsmath,mleftright}
\usepackage{unicode-math}
\usepackage{Baskervaldx}
\setmathfont{Asana Math}[Scale=MatchLowercase]
\usepackage{xcolor}
\usepackage[colorlinks,allcolors=blue,linktocpage]{hyperref}
\begin{document}
\section{test}
Solve $y''(x)-3 y(x) = -x^2$ over $x=0\ldots1$ with boundary conditions
$x(0)=0$ and $x(1)=0$ using piecewise linear trial functions.
\end{document}
编译时出现错误:
! Undefined control sequence.
\g__um_prime_font_cmd_tl ->\l__um_font
l.17 Solve $y''(
x)-3 y(x) = -x^2$ over $x=0\ldots1$ with boundary conditions
?
再次更改包的顺序,错误就消失了。这就是为什么我在测试 Mico 的优秀代码时会遇到一些错误。
答案1
我认为\cprotect
在当前上下文中使用构成了对宏的严重滥用。此外,正如您所发现的,它无法正常工作,因为 pdf 查看器程序的书签不再正确生成。
由于你使用的是 LuaLaTeX,我建议你采用不同的方法,即,设置一个在非常早期阶段运行的 Lua 函数,即在 TeX 开始其常规处理例程之前。通过将 Lua 函数分配给 LuaTeX 的process_input_buffer
预处理器回调,它可以扫描\section
、和的所有实例\subsection
,并\subsubsection
自动识别任何和所有内联数学材料实例并将这些实例放在\texorpdfstring
指令中,本质上是“净化”数学表达式以供使用hyperref
书签例程。例如,
\subsection{$x^2+y^2=z^2$}
将被“动态”替换为
\subsection{\texorpdfstring{$x^2+y^2=z^2$}{x2+y2=z2}}
和
\section{$\cos\left(A+B\right)$ \textcolor{red}{and} $\sin\left(A+B\right)$}
将被即时替换为
\section{\texorpdfstring{$\cos\left(A+B\right)$}{cos(A+B)}
\textcolor{red}{and}
\texorpdfstring{$\sin\left(A+B\right)$}{sin(A+B)}}
以下代码提供了两个 LaTeX 实用宏和两个 Lua 函数。这两个 LaTeX 宏分别称为\texorpdfOn
和\texorpdfOff
;它们用于激活和停用名为 的 Lua 函数fix_headers
。激活后,即分配给 LuaTeX 的process_input_buffer
回调后,fix_headers
将检查所有输入行;每次遇到\section
、\subsection
或\subsubsection
或其“带星号”变体的实例时,Lua 函数接下来会通过搜索字符 的对来检查该命令的参数是否包含内联数学材料$
。如果匹配,则strip_math
调用名为 的辅助 Lua 函数来生成一个或多个实例
\texorpdfstring{$<unmodified math>$}{<sanitized math>}
\section
在、\subsection
等参数内。
这输入要求如下面所述:
每个分段命令及其参数必须位于同一输入行。这绝对是最严格的要求。
在任何给定的输入行中,都有最多一个
\section
、\subsection
或\subsubsection
或这些命令的带星号变体之一的实例。(这可能更像是一般的输入健全性检查。但是,我认为无论如何我都应该提一下。)没有包含分段指令的逐字材料实例,而分段指令又包含内联数学材料。例如,没有 的实例。(可以通过排除所有内联逐字材料和、和
\verb+\subsection{$1+1=2$}+
等环境的内容来放宽这一限制;如果在实践中存在这个问题,请提出新问题。或者,在到达逐字材料之前运行。稍后,退出逐字材料后,您可以再次运行。)verbatim
Verbatim
comment
\texorpdfOff
\texorpdfOn
文档中没有名为 等的命令
\Xsection
(\xyzsection
此要求主要是为了编程方便。如果需要,可以放宽此要求,而无需做太多额外工作。)\chapter
和的参数\chapter*
不包含内联数学材料。(此要求也可以放宽,不需要太多额外工作。)字符
$
用于分隔节标题中的内联数学材料。(的实例\$
,用于排版$
象征本身就是允许的。有无显示数学材料
\section
在、等论点中。特别是在、等论点中\subsection
没有 的实例。$$
\section
\subsection
\frac
不允许使用嵌套表达式。\frac
但是可以使用非嵌套表达式。以下形式的非嵌套表达式\frac{<numer>}{<denom>}
在书签中显示为(<numer>)/(<denom>)
。
我会祈祷这些输入要求不会太繁重。
% !TEX TS-program = lualatex
%% (compile twice to update the ToC and bookmarks)
\documentclass{book} % or some other suitable document class
\usepackage{luacode} % for 'luacode*' environment
\begin{luacode*}
function strip_math ( u )
-- Drop the '$' delimiters:
v = u:sub ( 2 , -2 )
-- Three types of math directives that need to be modified:
-- directives that need to be removed, e.g, \left and \biggr
-- directives that need to be modified, e.g., \mid and \prime
-- all others: just remove the leading backslash (\cos,\int,\log, ...)
-- Remove all fence-sizing instructions from the input stream:
v = v:gsub ("\\m?left" , "" )
v = v:gsub ("\\m?right", "" )
v = v:gsub ("\\[bB]igg?[lrm]?" , "" )
-- Replace "\frac{...}{...}" with inline-fraction notation:
v = v:gsub ("\\frac%s-(%b{})%s-(%b{})" , "(%1)/(%2)" )
-- Delete '_' and '^' characters from input stream:
v = v:gsub ("[%_%^]" , "" )
-- Change '\mid' to '|'
v = v:gsub ("\\mid" , "|" )
-- Change \prime to '
v = v:gsub ("\\prime" , "'" )
-- Finally, change '\int' to 'int', '\sum` to 'sum', '\det' to 'det', etc.
v = v:gsub ("\\(%a+)", "%1" )
-- Return a "\texorpdfstring" directive:
return "\\texorpdfstring{"..u.."}{"..v.."}"
end
function fix_headers ( s )
s = s:gsub ( "(\\%l-section[%*]?)%s-(%b{})" ,
function ( x , y )
-- Set aside all instances of "\$" (if any):
y = y:gsub ( "\\%$", "@@@@@@@@" )
-- Apply 'strip_math' function if inline-math found:
y = y:gsub ( "%b$$" , strip_math )
-- Restore instances of "\$":
y = y:gsub ( "@@@@@@@@" , "\\$" )
return x..y
end )
return s
end
\end{luacode*}
%% Define a couple of utility LaTeX macros:
\newcommand\texorpdfOn{\directlua{luatexbase.add_to_callback(
"process_input_buffer", fix_headers , "fix_headers" )}}
\newcommand\texorpdfOff{\directlua{luatexbase.remove_from_callback(
"process_input_buffer", "fix_headers" )}}
\usepackage{amsmath,mleftright}
\usepackage{unicode-math}
\setmainfont{Baskerville 10 Pro} % pick a suitable text font
\setmathfont{Asana Math}[Scale=MatchLowercase] % pick a suitable math font
\usepackage{xcolor}
\usepackage[colorlinks,allcolors=blue,linktocpage]{hyperref}
\begin{document}
\texorpdfOn % Activate the Lua function 'fix_headers'
\setcounter{secnumdepth}{3} % just for this example
\setcounter{tocdepth}{3}
\tableofcontents
\chapter{AAA}
\section{$\cos\left( A+B\right) $ \textcolor{red}{and} $\sin\left( A+B\right) $}
\subsection{$\det\bigl(A\bigr)$}
\subsubsection{$\ln \mleft[x\mright]$}
\subsubsection{$x^2+y^2=z^2$}
\subsection{$\int f(x)\,dx$}
\section{\textcolor{violet}{Hello World}}
\section{$\frac{a+b}{c+d}$ or $\frac{u}{v}$}
\subsection{$1+1+1=3$, and \$1+\$1+\$1=\textdollar3}
\subsection{Solve numerically the ODE $u''''+u=f$ using\dots}
\end{document}
答案2
该问题并不取决于特定的字体,而是取决于unicode-math
。
使用\cprotect
并不是解决方案:标题中没有任何逐字逐句的内容。
你可以逐步收集“有问题的”命令:
\documentclass[12pt]{book}
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
%\setmathfont{Asana Math}
%\usepackage{Baskervaldx}
\usepackage{amsmath}
\usepackage{hyperref}
\pdfstringdefDisableCommands{%
\def\sin{sin}\def\cos{cos}% <-- add here
\let\left\relax
\let\right\relax
}
\begin{document}
\tableofcontents
\chapter{A}
\section{$\cos\left( A+B\right) $ and $\sin\left( A+B\right) $}%
\subsection{C}
stuff
\subsection{D}
stuff
\end{document}
答案3
\cos 和 \sin 的问题可以通过使 \operator@font 更强大来解决。我在 unicode-math github 上为此开了一个问题https://github.com/wspr/unicode-math/issues/550
这解决了一问题,确实如此不是意味着每个数学运算都不会出错。
\documentclass[12pt]{book}
\usepackage{unicode-math}
\setmathfont{Asana Math}
\usepackage{hyperref}
\makeatletter
\ExplSyntaxOn
\cs_set_protected:Npn \operator@font
{
\__um_switch_to:n {literal}
\__um_fontswitch:n { \g__um_operator_mathfont_tl }
}
\ExplSyntaxOff
\makeatother
\begin{document}
\tableofcontents
\chapter{A}
\section{$\cos\left( A+B\right) $ and $\sin\left( A+B\right) $}%
\end{document}
通过使用以下选项加载 hyperref 可以避免 \zeta 和类似问题psdextra
:
\documentclass{article}
\usepackage{unicode-math}
\usepackage[psdextra]{hyperref}
\begin{document}
\section{$\zeta$}
\end{document}