我使用的罗马下标下划线重新定义(见示例)阻止我在eqnarray
环境中定义标签。我该如何解决这个问题?(当我使用时不会出现此问题align
,但我现在确实需要使用eqnarray
)。谢谢,豪尔赫。
例子:
\documentclass[twocolumn]{article}
\usepackage{amsmath}
\catcode`_=\active
\newcommand{_}{\ifmmode\expandafter\sbrm\else\string_\fi}
\newcommand{\sbrm}[1]{\sb{\mathrm{#1}}}
\begin{document}
This compiles:
\begin{align}
1 \neq 2
\label{my_label_1}
\end{align}
This doesn't:
\begin{eqnarray}
1 \neq 2
\label{my_label_2}
\end{eqnarray}
\end{document}
编译错误:
! Missing \endcsname inserted.
<to be read again>
\sb
l.3 ...mathrm {l}}abel\sb {\mathrm {2}}}{{2}{1}}
答案1
您可能已经知道答案的第一部分。第一个之所以有效,是因为标签处于文本模式,因此_
是_
。另一方面,第二个处于数学模式,因此_
是\sbrm
,然后事情就变得疯狂了。为了确保您可以\label
在加载之前重新定义amsmath
以使其与您对话:
\makeatletter
\def\label#1{%
\ifmmode
\typeout{^^JLabel in math mode for \@currenvir^^J}
\else
\typeout{^^JLabel in horizontal mode for \@currenvir^^J}
\fi
\@bsphack
\protected@write\@auxout{}%
{\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
\@esphack}
控制台屏幕将显示:
Label in horizontal mode for align
Label in math mode for eqnarray
就在抛出错误之前。
这是因为实现方式不同。align
来自amsmath
,所以他们可能更喜欢在水平模式下制作标签,而eqnarray
来自 LaTeX 内核。
重新定义eqnarray
使\label
文本模式看起来太多了。也许我们可以做点什么\label
……
请注意,我只是正在做这个,不推荐!
旧解决方案:
我们可以让它将的转换 \catcode
为_
其他的,这样我们就不会使用它的宏含义:
\def\label{%
\begingroup
\catcode`\_=12
\l@bel}
然后我们定义一个内部函数\l@bel
来标记参数并写入.aux
:
\def\l@bel#1{%
\@bsphack
\protected@write\@auxout{}%
{\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
\@esphack
\endgroup}
请注意,这些更改必须在加载之前完成,amsmath
因为它存储了当前的定义,\label
并且您希望它记住所做的更改。
新解决方案:
实际上,更强大的方法是不要重新定义内部\label
,而是仅用 catcode 更改所需的内容对其进行修补,因为某些包(hyperref
,我正在看你)可能会删除你的定义。
使用etoolbox
我们可以设计一个hyperref
兼容的解决方案。我们将 的旧含义存储\label
在 中\old@ltx@label
,然后创建\label
与之前相同的包装器,然后将 附加到\endgroup
,\old@ltx@label
所有这些都在 之后\begin{document}
(不是在 \begin{document}
):
\usepackage{etoolbox}
\AfterEndPreamble{%
\let\old@ltx@label\label
\def\label{%
\begingroup
\catcode`\_=12
\old@ltx@label}%
\apptocmd\old@ltx@label\endgroup{}{}
}
不过,我还没有用其他交叉引用包测试过这个解决方案。它可能会破坏一些东西。
可编译文档:
\documentclass[twocolumn]{article}
\makeatletter
\def\label{%
\begingroup
\catcode`\_=12
\l@bel}
\def\l@bel#1{%
\@bsphack
\protected@write\@auxout{}%
{\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
\@esphack
\endgroup}
\makeatother
\usepackage{amsmath}
\catcode`_=\active
\newcommand{_}{\ifmmode\expandafter\sbrm\else\string_\fi}
\newcommand{\sbrm}[1]{\sb{\mathrm{#1}}}
\begin{document}
This compiles:
\begin{align}
1 \neq 2
\label{my_label_1}
\end{align}
This doesn't:
\begin{eqnarray}
1 \neq 2
\label{my_label_2}
\end{eqnarray}
Now both equation~\eqref{my_label_1} and~\eqref{my_label_2} compile :)
\end{document}
答案2
我认为这只是出于学术兴趣,因为eqnarray
永远不应该被使用。
您采取了错误的方法来解决问题:因为您希望下划线在文本中打印为其自身,所以最简单的方法就是使其具有数学活性。
\documentclass[twocolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{amsmath}
\newcommand{\sbrm}[1]{\sb{\mathrm{#1}}}
\catcode`_=12
\begingroup\lccode`~=`_ \lowercase{\endgroup\let~}\sbrm
\AtBeginDocument{\mathcode`_="8000 }
\begin{document}
This_compiles:
\begin{align}
1 \neq 2
\label{my_label_1}
\end{align}
This_compiles_too:
\begin{eqnarray}
1 \neq 2
\label{my_label_2}
\end{eqnarray}
\end{document}