梅威瑟:
\documentclass{minimal}
\usepackage{commath, tikz}
\begin{document}
\begin{tikzpicture}
\node {$:$};
\end{tikzpicture}
\end{document}
当我编译这个文件时,pdfTeX 进入无限循环。为什么?
答案1
commath
问题是 TikZ 覆盖了(我不建议使用)给出的活动冒号的定义。
这应该可以:
\documentclass{minimal}
\usepackage{commath,tikz}
\makeatletter
\protected\def\tikz@nonactivecolon{\ifmmode\mathrel{\mathop\ordinarycolon}\else:\fi}
\makeatother
\begin{document}
\begin{tikzpicture}
\node {$:$};
\end{tikzpicture}
\end{document}
mathtools
请注意,如果加载了,也会发生同样的情况,并且
\mathtoolsset{centercolon}
被使用。但同样的解决方法也有效。
这是一个独立于已加载的包运行的版本,当然假设已经tikz
加载了该包。
\documentclass{article}
\usepackage[french]{babel}
\usepackage{mathtools}\mathtoolsset{centercolon}
%\usepackage{commath}
\usepackage{tikz}
\usepackage{etoolbox}
\makeatletter
\AtEndPreamble{
\ifnum\mathcode`\:=\string"8000
\begingroup\lccode`\~=`\:
\lowercase{\endgroup\let\math@colon@meaning~}
\else
\expandafter\let\expandafter\math@colon@meaning\string:
\fi
}
\AtBeginDocument{
\ifnum\catcode`\:=\active
\letcs\text@colon@meaning{active@char\string:}
\else
\expandafter\let\expandafter\text@colon@meaning\string:
\fi
\protected\def\tikz@nonactivecolon{%
\ifmmode
\expandafter\math@colon@meaning
\else
\expandafter\text@colon@meaning
\fi}
\begingroup\lccode`\~=`\:
\lowercase{\endgroup\let~\tikz@nonactivecolon}
}
\makeatother
\begin{document}
French: colon
\begin{tikzpicture}
\node {$:=$};
\end{tikzpicture}
\end{document}
答案2
到目前为止,我对最初的答案做了三处修改:
我添加了一些代码来解决 Babel 引发的问题,当它使一个字符(这里是冒号)活跃时,其他一些包也使它在数学上活跃;我想确保
\label
并且\ref
可以在所有情况下使用(包括语言切换),这很困难。egreg
在第一次编辑中,我基本上也从补丁复制到了\tikz@nonactivecolon
。在第二次编辑中,我更详细地阐述了这个 TikZ 补丁,因为我也希望\label
和\ref
可以在 tikz 图片中使用,并且具有潜在的活动 + 数学上的活动冒号。我回来时有了简化 Babel 补丁的想法,但后来我意识到它缺少了一个内容
\fi
;然后它变得非常混乱,因为TeX
当我添加它时出现了错误,我意识到它没有正确地\else
与相应的\if...
...[更新:事实上,我犯了一个编码错误,这个错误源于我一直对TeX
扫描条件语句时到底做了什么的误解。我吸取了教训]...我把所有的东西都移到了一个专用宏中,这个宏是首先定义的...[这确实是对这个实现问题的正确修复]。好的,我确实有一个较短的版本,
\dotheactivecatcodesubroutine
我将其附加在本答案的最底部。我没有尝试解释,因为它让我头疼。它似乎工作得很好。我保留了原来的。要研究它们中的任何一个的效果,可以向文档正文中添加一些内容,例如{\tt家庭
\expandafter\meaning\csname 用户@active\string:\endcsname
\expandafter\meaning\csname normal@char\string:\endcsname}
根据是否
mathtools
加载来查看补丁对 Babel 做了什么。我在这个答案的末尾添加了
TikZ
补丁的一个轻微变体,用于 (Babel) catcode 激活和 mathcode 激活冒号的情况。这使用 。这似乎也有效,并且具有优点或缺点,即冒号现在充当图片内部(和数学模式外部)的\bbl@deactivate
法语(或其他语言使其激活)冒号。node
tikz
commath
当问题出现时,说它写得不好有点苛刻,因为tikz
没有检查冒号的数学激活!
Babel 也有同样的问题。试试
\documentclass{article}
\usepackage[french]{babel}
\mathcode`:="8000
{\catcode`:\active \gdef:{\ifmmode A\else B\fi}}
\begin{document}
a:b
\end{document}
到目前为止一切顺利。在文档开头,冒号通过frenchb.sty
的服务变为活动状态babel
。您可以看到冒号前面的额外空格。
然后尝试将$a:b$
代码添加到:它陷入了无限循环。为什么?因为babel+frenchb
定义活动冒号以扩展到后面跟着的某个空间\string:
,即带有类型的冒号other
(类别代码 12),这应该是安全的。
但not
在数学模式下它一定是安全的!因为我们可以让字符被声明为数学活动,这意味着虽然不一定是类别代码 13,但它仍然(大部分)表现得像它一样。所以\string:
看起来很安全的其实不是!试试这个
\documentclass{article}
\mathcode`:="8000
\catcode`:\active \gdef:{\ifmmode MATH\else TEXT\fi}
\begin{document}
: % active colon gives TEXT
$:$ % active colon gives MATH
\string: % category 12 colon gives ... colon
$\string:$ % prints MATH! this shows that it was treated as being active!
\end{document}
现在commath
可以对其数学活动冒号进行所有您想要的定义,但它们都无法解决问题! 所做的定义commath
与无限循环无关! 纯粹是因为冒号在数学上是活动的,导致了无限循环,因为人们认为(由tikz
或 由frenchb+babel
)第 12 类字符是安全的。
确实,补丁egreg
应用于的宏,而tikz
不是的宏commath
!
我一直在努力为 Babel+math 活动字符和 TikZ(这要容易得多)提供补丁。我发布了它,尽管一些问题很可能仍然存在(我现在很累,工作速度越来越慢,直到深夜......)。我应该说我把所有的精力都花在了 Babel 上,而关于 TikZ,我只是看得很快。所以我可能忽略了很多东西(尤其是因为我从未使用过 TikZ。)Babel 有很多困难的事情,但最棘手的是当一个字符(这里是冒号)在数学上是活动的,并且是 catcode 活动的,但随后用户切换语言并且该字符在新语言中是正常的(但它仍然是 catcode 活动的)。解决方案必须与在数学模式下使用\label
和兼容\ref
。Babel 在处理活动字符时非常精致和小心,但根本不关注数学模式。(除了插入符号或素数之类的东西)。(我说已经晚了,所以我最后一句话可能太快和肤浅了)
我不使用etoolbox
。
\documentclass[fleqn]{article}
\usepackage[english,french]{babel} % can be commented out
\usepackage{mathtools}\mathtoolsset{centercolon} % can be commented out
\usepackage{tikz}
% this goes BEFORE \begin{document} and AFTER all packages
% such as mathtools which may let : be mathematically active
% (hopefully they do it already in the preamble).
\makeatletter
\ifnum\mathcode`\:=\string"8000
\begingroup\lccode`\~=`\: % and the tilde ~ must be active here.
\lowercase{\endgroup
\let\mathactive@colon@meaning~}
\fi
\makeatother
\makeatletter
% The next macro will be used at begin document (so after Babel
% has done its activation of characters, depending on the language)
% I had to move it here because of absolutely uncomprehensible
% problems with the parsing of the conditionals
% (adding braces changed nothing, I used `tracingcommands2` to
% confirm that TeX was taking the wrong `\else` but so far I have
% not understood why.)
% If Babel is not loaded what is done here does no harm.
% But it does no good either.
%
% Note: recent versions of frenchb.ldf do not use active characters
% under XeTeX but \XeTeXinterchartoks, which are no-op in math
% mode
%
% The characters activated by Babel do not check for math mode (except
% possibly the caret and the prime and maybe a few others, I should
% check in babel.pdf), it is up to the language definition
% file to do so. For example the
% extra spacing in front of !?;: is put by `frenchb`
% only in horizontal mode, not
% in math mode. In math mode the colon is just a standard category 12
% colon.
%
% But this creates an infinite loop is the colon is also
% mathematically active!
%
% The following cures this. It will let the
% colon act either as the standard category 12 colon or, if
% mathtools or another package has made the colon mathematically
% active (in the preamble) it will then use that definition.
%
% Let's store the Babel active and non-active versions,
% [nota bene: the ``normal char'' is the meaning to which the
% active character expands when the user switches languages to one
% where the character is not activated. The character remains
% active in the sense of catcode throughout the document except if
% the user uses \shorthandoff which really sets the catcode to 12.
% The following should be compatible with language changes. ]
%
% Babel uses \active@char: to let \user@active: become
% \normal@char: when it is used inside \ref, \newlabel, \bibcite...
% so to benefit from this we store the current
% meaning of \user@active:, and we do not modify \active@char:.
%
% The Babel definition of the active character
% puts a prefix in front of \active@char: (or \normal@char:) which
% results in first expansion of the active character :
% to be itself preceded
% by a \protect or \noexpand, or sometimes \active@char:. (so\label{eq:1}
% works ).
%
% On the other hand $\ref{eq:1}$ works for another reason:
% the \active@char: then expands to be \normal@char: hence
% to a category code 12 :. The mathcode is not a problem because this
% is inside \csname...\endcsname.
%
% If the user has switched to a language where the colon is
% `normal', the character remains active but when not
% protected expands to \normal@char: hence a category 12 :. And
% we are then doomed if the mathcode is 32768. Infinite loop.
%
% As \ref{eq:1} will make use of \normal@char: which then must expand
% to a category 12 colon, our possibilities to modify \normal@char:
% are greatly limited. As Babel has patched \ref and similar macros
% to set the \if@safe@actives flag to be true, we can test for it.
% We thus leave \normal@char: untouched except if \if@safe@actives if
% false (this takes care of \ref) and if \protect is
% \@typeset@protect: and only then we let \normal@char: use
% \mathactive@colon@meaning.
%
\def\dotheactivecatcodesubroutine{%
\expandafter\let\expandafter\original@user@active@colon
\csname user@active\string:\endcsname
\expandafter\let\expandafter\original@normal@char@colon
\csname normal@char\string:\endcsname
% should just be : with catcode 12
\ifnum\mathcode`\:=\string"8000
\expandafter\def\csname user@active\string:\endcsname{%
\ifmmode
\expandafter\mathactive@colon@meaning
\else
\expandafter\original@user@active@colon
\fi}
\def\hip@hop##1##2##3##4##5{##2##3##4##1}
\expandafter\def\csname normal@char\string:\endcsname{%
\ifmmode
\if@safe@actives\else
\ifx\protect\@typeset@protect % <-- this is probably superfluous
\hip@hop\mathactive@colon@meaning
\fi
\fi
\fi
\original@normal@char@colon}
\else
% here we have no problem of mathcode, but we would also like to
% annihilate (in a reasonable manner) the effects in math
% mode of the Babel activation of the character (here the colon).
\expandafter\def\csname user@active\string:\endcsname{%
\ifmmode
\expandafter\original@normal@char@colon
\else
\expandafter\original@user@active@colon
\fi}
\fi}
\AtBeginDocument{
\ifnum\catcode`\:=\active % We assume it is Babel+frenchb which is
% responsible for this
\dotheactivecatcodesubroutine
\fi
%
% if the character is not active, I will assume it will not be
% activated later by Babel (I will have to check the
% documentation). But we still have some problems
% with TikZ.... Indeed it seems that tikz
% `deactivates' the colon by re-defining its active version to
% expand to the category 12 colon:
% \def:{\tikz@nonactivecolon}% see tikz.code.tex 1521--1525&1439
% In the process the mathtools definition is thus overwritten
% but the mathcode is left to 32768... so the colon in math
% expands exactly as if it was active hence to
% \tikz@nonactivecolon which expands to the category 12 colon
% but don't forget the mathcode.... INFINITE LOOP.
\ifnum\mathcode`:=\string"8000
% if the colon is not mathematically active we don't have
% to do anything additional for TikZ now.
\@ifpackageloaded{tikz}
{%
% We have to distinguish the case of a catcode active colon.
% We are in that case in deep trouble
% Because TikZ does not try to modify the catcode (perhaps
% impossible due to argument parsing, I don't know) but
% redefines the active colon, we have to make sure this definition
% is safe with the math active colon. For this we simulate a
% switch to a language where the colon is `normal' in the sense
% of Babel, because we already solved the problem there. So we
% import that solution (of course this is assuming that the
% colon is active because of Babel in the first place).
%
% The following was done to make sure \label and \ref were usable
% inside tikz pictures, but perhaps this is not licit practice?
% (I don't know TikZ)
\ifnum\catcode`:=\active
\begingroup\lccode`~=`:
\lowercase{\endgroup
\let\original@babelactivecolon~
\g@addto@macro\tikz@deactivatthings{%
\expandafter\expandafter\expandafter\let
\expandafter\expandafter
\csname active@char\string:\endcsname
\csname normal@char\string:\endcsname
\def~{\original@babelactivecolon}}}
\else % colon is not catcode active
% in this branch the active colon will only be invoked in math mode
% because of the mathcode
% as the mathcode is not looked at in an \edef, \write, or a
% \csname.. \endcsname, I think I don't need the e-TeX \protected
\let\original@tikz@nonactivecolon\tikz@nonactivecolon
\def\tikz@nonactivecolon{%
\ifmmode
\expandafter\mathactive@colon@meaning
\else
\expandafter\original@tikz@nonactivecolon
\fi}
\fi}{}
\fi % end of TikZ patching for colon with mathcode 32768
} % end of AtBeginDocument
\makeatother
\begin{document}
\newcounter{testcounter}
\makeatletter
\@ifundefined{shorthandon}{}{French}%
\makeatother
: colon (:)
Math $:= (:)$ colon
Tikzpicture
\begin{tikzpicture}
\node {\refstepcounter{testcounter} a:b $ \label{pic:1} a:b $};
\end{tikzpicture}
\begin{tikzpicture}
\node {\refstepcounter{testcounter} c:d $ \label{pic:2} a:b \ref{pic:1}$};
\end{tikzpicture}
\begin{equation}
\label{eq:1}
a := b
\end{equation}
\begin{equation}
\label{eq:2}
b := a\quad (\mbox{see equation}\ \ref{eq:1})
\end{equation}
At the end of this manuscript we will have established equation \ref{eq:2}
starting from equation \ref{eq:1}.
\makeatletter
\@ifundefined{shorthandon}{}{\shorthandoff{:}not French anymore}%
\makeatother
: colon (:)
Math $:= (:)$ colon
Tikzpicture
\begin{tikzpicture}
\node {\refstepcounter{testcounter} d:e $ \label{pic:3} a:b \ref{pic:2}$};
\end{tikzpicture}
\begin{tikzpicture}
\node {\refstepcounter{testcounter} f:g $ \label{pic:4} a:b \ref{pic:3}$};
\end{tikzpicture}
\begin{equation}
\label{eq:3}
c := a\quad (\mbox{to be deduced from}\ \ref{eq:2})
\end{equation}
\makeatletter
\@ifundefined{shorthandon}{}{\shorthandon{:}}
\@ifundefined{shorthandon}{}{\selectlanguage{english}English}%
\makeatother
: colon (:)
Math $:= (:)$ colon
Tikzpicture
\begin{tikzpicture}
\node {\refstepcounter{testcounter} k:l $ \label{pic:5} a:b \ref{pic:4}$};
\end{tikzpicture}
\begin{tikzpicture}
\node {\refstepcounter{testcounter} m:n $ a:b \ref{pic:5}$};
\end{tikzpicture}
\begin{equation}
\label{eq:4}
c := b\quad (\mbox{to be deduced from}\ \ref{eq:3})
\end{equation}
\end{document}
替代版本\dotheactivecatcodesubroutine
:
\def\dotheactivecatcodesubroutine{%
\expandafter\let\expandafter\original@user@active@colon
\csname user@active\string:\endcsname
\expandafter\let\expandafter\original@normal@char@colon
\csname normal@char\string:\endcsname
% should just be : with catcode 12
\expandafter\expandafter\expandafter
\def\expandafter\expandafter
\csname user@active\string:\endcsname
\expandafter{\expandafter
\ifmmode
\expandafter\expandafter
\csname normal@char\string:\endcsname
\else
\expandafter\original@user@active@colon
\fi}
\def\hip@hop##1##2##3##4##5{##2##3##4##1}
\ifnum\mathcode`\:=\string"8000
\expandafter\def\csname normal@char\string:\endcsname{%
\ifmmode
\if@safe@actives\else
\ifx\protect\@typeset@protect % <-- this is probably superfluous
\hip@hop\mathactive@colon@meaning
\fi
\fi
\fi
\original@normal@char@colon}
\fi
}
该版本的TikZ
补丁更简单。它的效果似乎是它像另一个补丁一样避免了错误,但这次冒号在 中充当了法式冒号node
。我没有深入研究,tikz.code.tex
但似乎确实如此\tikz@installcommands
,然后\tikz@uninstallcommands
重新建立了活动冒号的初始定义。避免了无限循环。
\@ifpackageloaded{tikz}
{%
\ifnum\catcode`:=\active
\begingroup\lccode`~=`:
\lowercase{\endgroup
\g@addto@macro\tikz@deactivatthings{\bbl@deactivate~}}%
\else
\let\original@tikz@nonactivecolon\tikz@nonactivecolon
\def\tikz@nonactivecolon{%
\ifmmode
\expandafter\mathactive@colon@meaning
\else
\expandafter\original@tikz@nonactivecolon
\fi}%
\fi}{}
答案3
我花了几个小时调试这个。正如@egreg 已经指出的那样在他的评论中,commath
是一个写得不好的包。它试图通过以下方式修复 := 的对齐:
\mathchardef\ordinarycolon\mathcode`\:
\mathcode`\:=\string"8000
\begingroup \catcode`\:=\active
\gdef:{\mathrel{\mathop\ordinarycolon}}
\endgroup
不幸的是,这个 hack 并不完美,会导致 TikZ 节点无限循环。我不知道错误的确切解释,但你最好将命令定义从 commath.sty 复制到你的序言中,或者创建 .sty 文件的本地副本并删除这些行。
是否有人知道类似的 hack 来修复 := 并且它也可以在 TikZ 节点中使用?