我开始因为这个我不知道如何解决的奇怪错误而失去理智。我用希伯来语的乳胶做作业,并用它babel
来设置它。我有一个自定义包和类来定义我的风格和命令。经过几个小时的努力让它编译而没有错误,我发现它\Longrightarrow
坏了:
我尝试创建一个最小的例子来重现这个问题:
% !TeX spellcheck = he_HE
\documentclass[a4paper, 12pt]{extarticle}
\usepackage{amsmath}
\usepackage{enumitem}
\usepackage{witharrows}
\usepackage[bidi=basic, provide=*]{babel}
\babelprovide[alph=letters, Alph=letters]{hebrew}
\babelprovide{english}
\babelfont[hebrew]{rm}[Renderer=Harfbuzz, ItalicFont=*-Regular, ItalicFeatures={FakeSlant=0.3}]{Assistant}
\babelfont[hebrew]{sf}[Renderer=Harfbuzz, ItalicFont=*-Regular, ItalicFeatures={FakeSlant=0.3}]{Assistant}
\babelfont[hebrew]{tt}[Renderer=Harfbuzz, ItalicFont=*-Regular, ItalicFeatures={FakeSlant=0.3}]{Assistant}
\AddToHook{begindocument/end}{\selectlanguage{hebrew}}
\begin{document}
דוגמה \textit{לחישוב}:
\begin{DispWithArrows*}
A &= (a + b)^2 \Arrow{נפתח את הסוגריים בביטוי} \\
&= a^2 + 2ab + b^2
\end{DispWithArrows*}
\underline{דוגמה} \textbf{נוספת}:
\begin{align*}
A &= (a + b)^2\\
&= a^2 + 2ab + b^2
\end{align*}
\begin{otherlanguage}{english}
Some English example.
\end{otherlanguage}
\begin{enumerate}[leftmargin=*, label=\alph*.]
\item
בדיקה ראשונה.
\item
בדיקה שנייה.
\end{enumerate}
\[ AB = I \Longrightarrow B = A^{-1} \]
\end{document}
我检查了代码,试图禁用单个功能,但找不到这个问题的根源。处理的代码babel
与上面示例中的代码相同。以下是我的文件的精简版本:
my-style.sty
:
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{my-style}[2023/03/06 My personal style and custom commands]
\RequirePackage[table]{xcolor}
\RequirePackage{tikz}
\RequirePackage{tkz-base, tkz-euclide}
\RequirePackage{pgfplots}
\RequirePackage{graphicx}
\RequirePackage[most]{tcolorbox}
\RequirePackage{wrapfig}
\RequirePackage{titlesec}
\RequirePackage{xifthen}
\RequirePackage{xparse}
\RequirePackage{geometry}
\RequirePackage{amsmath}
\RequirePackage{amsfonts}
\RequirePackage{amssymb}
\RequirePackage{amsthm}
\RequirePackage{mathrsfs}
\RequirePackage{enumitem}
\RequirePackage{moreenum}
\RequirePackage{bm}
\RequirePackage{upgreek}
\RequirePackage[euler]{textgreek}
\RequirePackage{import}
\RequirePackage{esint}
\RequirePackage{mathtools}
\RequirePackage[thicklines]{cancel}
\RequirePackage[per-mode=fraction, exponent-product=\cdot]{siunitx}
\RequirePackage[italicdiff]{physics}
\RequirePackage{nicefrac}
\RequirePackage{parskip}
\RequirePackage{setspace}
\RequirePackage{dsfont}
\RequirePackage{etoolbox}
\RequirePackage[bottom]{footmisc}
\RequirePackage{multicol}
\RequirePackage{ulem}
\RequirePackage{pgfkeys}
\RequirePackage{nicematrix}
\RequirePackage{witharrows}
% Hebrew option
\newboolean{hebrew}
\setboolean{hebrew}{false}
\DeclareOption{hebrew}{\setboolean{hebrew}{true}}
\DeclareOption*{\PackageWarning{my-style}{Unknown '\CurrentOption'}}
\ProcessOptions\relax
% Font and lanuguage settings
\RequirePackage[bidi=basic, provide=*]{babel}
\babelprovide{english}
\babelprovide[alph=letters, Alph=letters]{hebrew}
\babelfont[hebrew]{rm}[Renderer=Harfbuzz, ItalicFont=*-Regular, ItalicFeatures={FakeSlant=0.3}]{Assistant}
\babelfont[hebrew]{sf}[Renderer=Harfbuzz, ItalicFont=*-Regular, ItalicFeatures={FakeSlant=0.3}]{Assistant}
\babelfont[hebrew]{tt}[Renderer=Harfbuzz, ItalicFont=*-Regular, ItalicFeatures={FakeSlant=0.3}]{Assistant}
\ifthenelse{\boolean{hebrew}}{
\AddToHook{begindocument/end}{\selectlanguage{hebrew}}
}{
\AddToHook{begindocument/end}{\selectlanguage{english}}
}
% witharrows options
\WithArrowsOptions{displaystyle}
\tikzset{
WithArrows/arrow/.append style = {
font= \small
}
}
\RequirePackage{hyperref}
\RequirePackage{fancyhdr}
\hypersetup{
colorlinks,
linkcolor=blue
}
\NewDocumentCommand{\OverSet}{ O{0cm} m m }{
\overset{\raise #1 \hbox{\(#2\)}}{#3}
}
\NewDocumentCommand{\UnderSet}{ O{0cm} m m }{
\underset{\lower #1 \hbox{\(#2\)}}{#3}
}
\NewDocumentCommand{\claptext}{ m }{\mathclap{\text{#1}}}
\NewDocumentCommand{\Transpose}{ s m }{
{\IfBooleanTF{#1}{\pqty{#2}}{#2}}^{\mathrm{t}}
}
\NewDocumentCommand{\InverseTranspose}{ s m }{
{\IfBooleanTF{#1}{\pqty{#2}}{#2}}^{-\mathrm{t}}
}
\NewDocumentCommand{\HermitianTranspose}{ s m }{
{\IfBooleanTF{#1}{\pqty{#2}}{#2}}^{\dagger}
}
\NewDocumentCommand{\InverseHermitianTranspose}{ s m }{
{\IfBooleanTF{#1}{\pqty{#2}}{#2}}^{-\dagger}
}
\NewDocumentCommand{\Conjugate}{ s m }{
\IfBooleanTF{#1}{\pqty{#2}}{#2}^{\ast}
}
% Physics commands
\NewDocumentCommand{\IdentityOperator}{}{\hat{I}}
\NewDocumentCommand{\Change}{ m }{\mathop{\Delta#1}}
homework.cls
:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{homework}[2022/11/01 My custom class for homework]
\LoadClass[a4paper, 12pt]{extarticle}
\RequirePackage{my-style}
\DeclareOption{hebrew}{\PassOptionsToPackage{hebrew}{my-style}}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{extarticle}}
\ProcessOptions\relax
\geometry{left=2cm, right=2cm, top=2cm, bottom=2cm}
% HomeWork options
\NewExpandableDocumentCommand{\Course}{}{}
\NewExpandableDocumentCommand{\StudentId}{}{#########}
\NewExpandableDocumentCommand{\StudentEmail}{}{[email protected]}
\NewExpandableDocumentCommand{\HWDate}{}{\today}
\ifthenelse{\boolean{hebrew}}{
\NewExpandableDocumentCommand{\Homework}{}{תרגיל בית}
\NewExpandableDocumentCommand{\StudentName}{}{שם הסטודנט}
}
{
\NewExpandableDocumentCommand{\Homework}{}{Homework assignment}
\NewExpandableDocumentCommand{\StudentName}{}{}
}
\NewDocumentCommand{\SetCourse}{ m }{\RenewDocumentCommand{\Course}{}{#1}}
\NewDocumentCommand{\SetHomework}{ m }{\RenewDocumentCommand{\Homework}{}{#1}}
\NewDocumentCommand{\SetStudentName}{ m }{\RenewDocumentCommand{\StudentName}{}{#1}}
\NewDocumentCommand{\SetStudentId}{ m }{\RenewDocumentCommand{\StudentId}{}{#1}}
\NewDocumentCommand{\SetStudentEmail}{ m }{\RenewDocumentCommand{\StudentEmail}{}{#1}}
\NewDocumentCommand{\SetHWDate}{ m }{\RenewDocumentCommand{\HWDate}{}{#1}}
% Styling customizations
\ifthenelse{\boolean{hebrew}}{
% Customize title
\titlelabel{חלק \thetitle}
}{}
\NewDocumentCommand{\Appendix}{ s }{
\IfBooleanF{#1}{\newpage}
\appendix
\ifthenelse{\boolean{hebrew}}{
\renewcommand{\thesection}{\arabic{section}}
% Customize title
\titlelabel{נספח \thetitle\quad}
}{}
}
% Homework functions
\newcounter{ProblemNum}
\newcounter{SubProblemNum}[ProblemNum]
\NewExpandableDocumentCommand{\TheProblemNum}{}{\arabic{ProblemNum}}
\ifthenelse{\boolean{hebrew}}{
\NewExpandableDocumentCommand{\TheSubProblemNum}{}{\alph{SubProblemNum}}
}{
\NewExpandableDocumentCommand{\TheSubProblemNum}{}{\arabic{SubProblemNum}}
}
\NewDocumentCommand{\Section}{ m }{
\phantomsection
\addcontentsline{toc}{section}{#1}
\section*{#1}
}
\NewDocumentCommand{\Problem}{ s o }{
\IfBooleanF{#1}{\newpage}
\stepcounter{ProblemNum}
\phantomsection
\ifthenelse{\boolean{hebrew}}{
\addcontentsline{toc}{subsection}{שאלה \TheProblemNum \IfNoValueF{#2}{\; #2}}
\subsection*{שאלה \TheProblemNum \IfNoValueF{#2}{\; #2}}
}{
\addcontentsline{toc}{subsection}{Question \TheProblemNum \IfNoValueF{#2}{\; #2}}
\subsection*{Question \TheProblemNum \IfNoValueF{#2}{\; #2}}
}
}
\NewDocumentCommand{\Solution}{}{
\phantomsection
\ifthenelse{\boolean{hebrew}}{
\addcontentsline{toc}{subsubsection}{פתרון}
\subsubsection*{פתרון}
}{
\addcontentsline{toc}{subsubsection}{Solution}
\subsubsection*{Solution}
}
}
\NewDocumentCommand{\Part}{ o }{
\IfNoValueTF{#1}{
\stepcounter{SubProblemNum}
\phantomsection
\ifthenelse{\boolean{hebrew}}{
\addcontentsline{toc}{subsubsection}{סעיף \texorpdfstring{\TheSubProblemNum}{\arabic{SubProblemNum}}}
\subsubsection*{סעיף \TheSubProblemNum}
}{
\addcontentsline{toc}{subsubsection}{Part \texorpdfstring{\TheSubProblemNum}{\arabic{SubProblemNum}}}
\subsubsection*{Part \TheSubProblemNum}
}
}{
\phantomsection
\ifthenelse{\boolean{hebrew}}{
\addcontentsline{toc}{subsubsection}{סעיף #1}
\subsubsection*{סעיף #1}
}{
\addcontentsline{toc}{subsubsection}{Part #1}
\subsubsection*{Part #1}
}
}
}
% Theorems and proofs
\ifthenelse{\boolean{hebrew}}{
\newtheorem{lemma}{למה}[ProblemNum]
}{
\newtheorem{lemma}{Lemma}[ProblemNum]
}
% Lists
\newlist{QuestionParts}{enumerate}{2}
\setlist[QuestionParts, 1]{align=left, leftmargin=*, label=\alph*.}
\setlist[QuestionParts, 2]{align=right, label=\arabic*.}
\newlist{SubParts}{enumerate}{1}
\setlist[SubParts, 1]{align=left, labelsep=0pt, leftmargin=0pt, labelwidth=*, label=\uline{חלק \arabic*}}
\NewDocumentCommand{\nitem}{ o }{
\IfNoValueTF{#1}{
\item\mbox{}\\
}{
\item[#1]\mbox{}\\
}
}
% Hyperref and fancyhdr setup
\hypersetup{
pdfauthor={\StudentName},
pdftitle={\Homework},
}
\pdfstringdefDisableCommands{\let\;\empty}
\setlength{\headheight}{15pt}
\ifthenelse{\boolean{hebrew}}{
\lhead{שאלה \arabic{ProblemNum}}
}{
\lhead{Question \arabic{ProblemNum}}
}
\chead{\Course}
\rhead{\Homework}
\lfoot{}
\cfoot{\thepage}
\rfoot{}
\pagestyle{fancy}
main.tex
:
% !TeX spellcheck = he_HE
\documentclass[hebrew]{homework}
\SetCourse{פיזיקה קוונטית 1}
\SetHomework{תרגיל בית 3}
\begin{document}
\tableofcontents
\import{./}{q1.tex}
\end{document}
q1.tex
:
% !TeX spellcheck = he_HE
\Problem[צמוד הרמיטי]
\[
\HermitianTranspose*{\hat{O}^{-1}}\HermitianTranspose{\hat{O}} = \HermitianTranspose*{\hat{O}\hat{O}^{-1}} = \HermitianTranspose{\IdentityOperator} = \IdentityOperator
\Longrightarrow \tcbhighmath{\HermitianTranspose*{\hat{O}^{-1}} = \pqty{\HermitianTranspose{\hat{O}}}^{-1}}
\]
编译main.tex
生成lualatex
第一张图片。正如我之前所说,我花了几个小时将这些文件与上面的示例进行比较,但找不到这个烦人的错误的来源。如果有人能弄清楚这里发生了什么以及如何解决它,我将不胜感激。
PS:我正在使用字体助手。
答案1
首先,由 生成的字形\Longrigtharrow
实际上不是一个字形,而是由⟹
( \Rightarrow
) 和组合=
而成,以延长其腿。问题是这两个字形来自不同的字体,如果没有默认字体,则无法使用它们的组合。
即使你的最小例子“不成功”,如果你仔细观察,你会发现腿部和头部实际上并没有完全重叠:
原因在于,您的最小示例使用了12pt
字体大小,并且虽然字体存在(加载lmr12
时使用的默认字体 ,使用命令时 babel 会加载该字体),但字体(箭头所在的位置)不存在,因此 LaTeX 可以缩放,但结果并不完美。fontspec
\babelfont
cmsy12
cmsy10
关于您的主文档,在某些情况下,fontspec 会将mathrm
字体定义为文档的主字体,这就是导致箭头腿看起来受到干扰的原因,它们实际上来自=
助手字体。
为了抑制这种情况,可以将选项传递给 fontspec,您可以通过在第一个 之前no-math
添加行来实现,或者您可以重命名文档类选项,或者您可以在 之前加载包。可能后者更可取,因为您使用的是默认字体大小。\PassOptionsToPackage{no-math}{fontspec}
\babelfont
unicode-math
babel
12pt
您无法通过最小示例获得类似结果的原因是,通过将选项传递hebrew
给 documentclass 减速,您实际上也将其传递给了所有包。
因为您本质上已经将\RequirePackage[hebrew,bidi=basic, provide=*]{babel}
其babel
视为hebrew
主要语言,并将主要字体设置为希伯来字体。
您可以使用更短的文档产生类似的结果:
\documentclass[hebrew]{article}
\usepackage{amsmath}
\usepackage[bidi=basic, provide=*]{babel}
\babelfont[hebrew]{rm}{Assistant}
\begin{document}
\[\Longrightarrow\]
\end{document}
答案2
更新了添加解决方法的答案。
除了将no-math
选项传递给fontspec
(via \PassOptionsToPackage
),或者确保所有加载的包都amsmath
在之后加载fontspec
(这很麻烦,例如tcolorbox
使用选项“most”就可以做到这一点),我认为最简单的方法是
\makeatletter\Umathcharnumdef\std@equal\Umathcodenum`\=\relax\makeatother
之后立即添加\begin{document}
。或添加
\makeatletter \AtBeginDocument{% \Umathcharnumdef\std@equal\Umathcodenum`\=\relax }% \makeatother
如果您使用的 LaTeX 至少是 2020 年 10 月之前的版本,则可以在序言中的任何地方使用,或者
\begin{document}
对于较旧的 LaTeX,则可以在之前使用。
您不需要担心\std@minus
(如果您阅读这个答案的其余部分,您会看到提到),因为fontspec
(据我检查)没有什么特别的-
。
这只是对非常好的补充回答由@UdiFogiel 撰写,因为我的评论太长,不适合作为评论。
比较以下几种情况:
- 一份 pdflatex 文档:
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{dejavu}
\begin{document}
a $\Longrightarrow$
\thispagestyle{empty}
\showoutput
\end{document}
% Local variables:
% TeX-engine: default
% End:
并且日志包含(不要担心)
它代表一个插槽,实际上是箭头所在的位置)
....\OT1/DejaVuSerif-TLF/m/n/12 a
....\glue 3.81479 plus 1.9068 minus 1.27199
....\mathon
....\OT1/cmr/m/n/12 =
....\hbox(0.0+0.0)x-1.99997
.....\kern -1.99997
....\OMS/cmsy/m/n/12 )
....\mathoff
- 现在我们尝试使用 luatex 和 fontspec 类似的东西:
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{fontspec}
\setmainfont{DejaVu Serif}
\begin{document}
a $\Longrightarrow$
\thispagestyle{empty}
\showoutput
\end{document}
% Local variables:
% TeX-engine: luatex
% End:
日志内容如下:
....\TU/DejaVuSerif(0)/m/n/12 a
....\glue(\spaceskip) 3.81445 plus 1.90723 minus 1.27148
....\mathon
....\TU/DejaVuSerif(0)/m/n/12 =
....\hbox(0.0+0.0)x-1.99997, direction TLT
.....\kern-1.99997 (italic)
....\OMS/cmsy/m/n/12 )
....\mathoff
- 与 2. 相同,但没有
amsmath
:
\documentclass[12pt]{article}
%\usepackage{amsmath}
\usepackage{fontspec}
\setmainfont{DejaVu Serif}
\begin{document}
a $\Longrightarrow$
\thispagestyle{empty}
\showoutput
\end{document}
% Local variables:
% TeX-engine: luatex
% End:
并且日志包含
....\TU/DejaVuSerif(0)/m/n/12 a
....\glue(\spaceskip) 3.81445 plus 1.90723 minus 1.27148
....\mathon
....\hbox(4.33081+0.0)x9.1388, direction TLT
.....\OT1/cmr/m/n/12 =
....\hbox(0.0+0.0)x-1.99997, direction TLT
.....\kern-1.99997 (italic)
....\OMS/cmsy/m/n/12 )
....\mathoff
请注意,在这些日志摘录中显示的“字体名称”实际上是 LaTeX“新字体选择方案(或系统?)NFSS”分配的宏名称。
因此,我们看到问题不仅仅在于其中一个,而在于和以及 Unicode 引擎fontspec
的组合。fontspec
amsmath
现在amsmath
的定义\Longrightarrow
是
\renewcommand{\Longrightarrow}{%
\DOTSB\protect\Relbar\protect\joinrel\Rightarrow}
并且的定义\Relbar
是
\ams@DeclareRobustCommand\Relbar{\mathrel\std@equal}
并且的定义\std@equal
稍微复杂一些
\@ifundefined{Umathcode}
{%
\mathchardef\std@minus\mathcode`\-\relax
\mathchardef\std@equal\mathcode`\=\relax
}
{%
\Umathcharnumdef\std@minus\Umathcodenum`\-\relax
\Umathcharnumdef\std@equal\Umathcodenum`\=\relax
}
\@ifundefined{Umathcode}
{%
\AtBeginDocument{%
\mathchardef\std@minus\mathcode`\-\relax
\mathchardef\std@equal\mathcode`\=\relax
}%
}
{%
\AtBeginDocument{%
\Umathcharnumdef\std@minus\Umathcodenum`\-\relax
\Umathcharnumdef\std@equal\Umathcodenum`\=\relax
}%
}
它表明这是数学模式中\std@equal
的别名,并坚持它在开始文档时重新进行定义。=
amsmath
如果没有 amsmath,我们也会得到类似的东西,\Relbar
只是后者的定义是一个扩展为的健壮宏\mathrel{=}
。所以基本上它看起来和上面的东西一样。
amsmath
那么为什么会有差异呢?在let's do的例子中
\makeatletter
a $\std@equal = \Longrightarrow$
那么输出是
。因此,amsmath 不遗余力地制造出\std@equal
相同=
的,但最终它们并不相同。如果没有 amsmath,箭头将使用\Relbar
将使用的内容\mathrel{=}
,并且不会出现不匹配的情况。
但这里发生的事情是,\std@equal
数学代码被冻结为等号,它映射到使用数学模式的“运算符”TeX 字体“系列”中的给定插槽。这样,fontspec
“运算符”就会被修改以匹配文档的罗马字体。同时,数学模式中的“运算符”fontspec
也会被修改为=
不是使用=
文本字体。但它不会修改 amsmath,\std@equal
因此最终将使用文档“罗马”字体。
fontspec
文件中“操作符”的修改fontspec-luatex.sty
:
\DeclareSymbolFont{operators}\g_fontspec_encoding_tl\g__fontspec_mathrm_tl\mddefault\shapedefault
本次修改fontspec
由=
:
\DeclareSymbolFont{legacymaths}{OT1}{cmr}{m}{n}
...
\DeclareMathSymbol{=}{\mathrel}{legacymaths}{61}
然后我们可以检查数学代码=
以及数学版本
> \symlegacymaths=\char"4.
l.8 \show\symlegacymaths
?
> 73400381.
l.9 \showthe\mathcode`=
?
> \temp=\Umathchar"3"04"00003D.
l.11 \show\temp
?
> \std@equal=\Umathchar"3"00"00003D.
l.12 \show\std@equal
?
我曾经用过这个
\makeatletter
\show\symlegacymaths
\showthe\mathcode`=
\Umathcharnumdef\temp\Umathcodenum`=\relax
\show\temp
\show\std@equal
=
通过别名来解开“Umathcode” \temp
,这可以确认=
现在取自“legacymaths”(编号 4),而\std@equal
仍然引用“operators”(编号 0)的字形。但“operators”现在映射到文档“roman”字体(在 OP 使用的例子中,它\babelfont
实际上是希伯来语的字体)。
结论:其中一个fontspec
必须amsmath
考虑到另一个的存在。这可能是一个已知的错误,已在fontspec
问题追踪器但我发现只有一个问题提及,amsmath
并且它已经关闭且不相关。