![Algorithm2e 关于字母 Q 的问题是什么?](https://linux22.com/image/290796/Algorithm2e%20%E5%85%B3%E4%BA%8E%E5%AD%97%E6%AF%8D%20Q%20%E7%9A%84%E9%97%AE%E9%A2%98%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F.png)
不,说真的。
以下 LaTeX 文档排版没有问题:
\documentclass{article}
\usepackage{algorithm2e}
\begin{document}
\begin{minipage}{\textwidth}
\begin{algorithm}[H]
\Begin(F){
}
\end{algorithm}
\end{minipage}
\end{document}
我想重点说一下这条\Begin(F)
线。以下是我的实验结果:
如果我用 替换它
\Begin(Q)
,则没有任何问题。如果我用 替换它
\Begin([x])
,仍然没有问题。但是,如果我将其替换为
\Begin([Q])
,就会发生奇怪的事情。我最终得到了一个以 开头的算法beginQ [Q]
,如下图所示:如果我用 替换它
\Begin($[Q]$)
,pdflatex 就会开始抱怨并且不知道如何排版文档。如果我用 pdflatex 替换它
\Begin($[x,Q]$)
仍然失败。如果我用 替换它
\Begin($[Q,x,r]$)
,pdflatex 会生成一个以 开头的算法beginx [Q,x,r]
。
如果我使用 Q 以外的字母,就不会出现这些问题。到底发生了什么?
编辑:我使用 TeX Live 2013 和最新版本(2013/01/06 v5.00)algorithm2e
。
答案1
我刚刚看了algorithm2e
源代码。您报告的行为可以追溯到名为\ifArgumentEmpty
(在 中定义algorithm2e.sty
) 的宏的定义,该宏会更改 (或者更确切地说,尝试改变) 大写字母的 catcode Q
:
\long\def\ifArgumentEmpty#1{\bgroup
\catcode`\Q=3
\catcode`\T=3
\long\def\@tempa##1##2Q##3##4##5T{##4}%
\xdef\@tempa{\@tempa#1QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T}%
\egroup\@tempa}
Q
如果通过用另一个字符替换所有实例来更改该宏的定义(A
在下面的代码中),则问题将出现在该其他字符上,但不再出现在字母 Q 上。
我对源代码不够熟悉,algorithm2e
无法给出比这个更好的解释。您可能应该就此问题与 Q 的维护者联系。
\documentclass{article}
\usepackage{algorithm2e}
\makeatletter
\long\def\ifArgumentEmpty#1{\bgroup
\catcode`\A=3
\catcode`\B=3
\long\def\@tempa##1##2A##3##4##5B{##4}%
\xdef\@tempa{\@tempa#1AA{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}B}%
\egroup\@tempa}
\makeatother
\begin{document}
\begin{minipage}{\textwidth}
\begin{algorithm}[H]
\Begin([A]){
}
\end{algorithm}
\begin{algorithm}[H]
\Begin([Q]){
}
\end{algorithm}
\end{minipage}
\end{document}
答案2
正如 Jubobs 正确诊断的那样,问题出在\ifArgumentEmpty
。他应该为查明问题而受到赞扬。以下是对该问题的分析和一些解决方法。
让我们看看\ifArgumentEmpty
应该做什么,至少在包作者的意图中。参数被吸收,并定义一个临时宏:
\long\def\@tempa#1#2Q#3#4#5T{#4}
因为我们在定义中,所以变成。然后的参数被#
传递给##
\ifArgumentEmpty
\xdef\@tempa{\@tempa#1QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T}
请注意,#1
当涉及到时,将是括号内的内容\Begin
。因此,让我们看看参数为空或只有空格的情况(空格将被忽略,因为第一个参数是\@tempa
无界的)。
如果#1
为空,TeX 会认为
\@tempa QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T
因此的第一个参数\@tempa
是Q
,第二个参数为空,第三个参数是\noexpand\@secondoftwo
,第四个参数是\noexpand\@firstoftwo
;第五个参数为空。
如果#1
非空,则它的第一个标记是 的第一个参数\@tempa
,其余(可能为零)标记是第二个参数,第三个参数是Q
,第四个参数是\noexpand\@secondoftwo
,第五个参数是\noexpand\@firstoftwo
。
所以\@tempa
展开后,\noexpand\@firstoftwo
在空的情况下保留,\noexpand\@secondoftwo
在非空的情况下保留。
理论上,Q
和的类别代码的改变T
应该确保这些标记不包含在的参数中\ifArgumentEmpty
。但在这个代码中,它们不具有程序员认为的类别代码 3。类别代码在定义时固定,定义宏时,两个标记是字母。指令\catcode`Q=3
和\catcode`T=3
根本不执行任何操作。
让我们看看当参数为[Q]
:TeX 认为
\@tempa [Q]QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T
的第一个参数\@tempa
是[
;第二个参数为空,第三个参数是]
,第四个参数是Q
,第五个参数是 ,直到 为止的其余部分T
。因此\@tempa
定义为Q
,而第二和第三个(明显的)参数\ifArgumentEmpty
也保留在输入流中,因为没有\@firstoftwo
或\@secondoftwo
来处理它们。
同样的问题也会出现,只要第二参数的标记\ifArgumentEmpty
是Q
。
这是一个正确的定义:
\makeatletter
\begingroup
\catcode`\Q=3
\catcode`\T=3
\long\gdef\ifArgumentEmpty#1{%
\long\def\@tempa##1##2Q##3##4##5T{##4}%
\edef\@tempa{\@tempa#1QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T}%
\@tempa
}
\endgroup
\makeatother
宏内部不需要组,也不需要\xdef
。
请注意,我们必须使用\gdef
来定义\ifArgumentEmpty
,以便本地化类别代码的变化。
测试例子。
\documentclass{article}
\usepackage{algorithm2e}
\begin{document}
\textbf{Original definition}
Empty: \ifArgumentEmpty{}{Empty}{Non empty}
Spaces: \ifArgumentEmpty{ }{Empty}{Non empty}
ABC: \ifArgumentEmpty{ABC}{Empty}{Non empty}
Q: \ifArgumentEmpty{Q}{Empty}{Non empty}
[Q]: \ifArgumentEmpty{[Q]}{Empty}{Non empty}
\bigskip
\makeatletter
\begingroup
\catcode`\Q=3
\catcode`\T=3
\long\gdef\ifArgumentEmpty#1{%
\long\def\@tempa##1##2Q##3##4##5T{##4}%
\edef\@tempa{\@tempa#1QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T}%
\@tempa
}
\endgroup
\makeatother
\textbf{Fixed definition}
Empty: \ifArgumentEmpty{}{Empty}{Non empty}
Spaces: \ifArgumentEmpty{ }{Empty}{Non empty}
ABC: \ifArgumentEmpty{ABC}{Empty}{Non empty}
Q: \ifArgumentEmpty{Q}{Empty}{Non empty}
[Q]: \ifArgumentEmpty{[Q]}{Empty}{Non empty}
\end{document}
请注意,在[Q]
原始定义行中,结果正是我所预测的:Q
是排版,然后也是Empty
和Non empty
。这也证明,如果仍然不清楚,Q
参数文本中的\@tempa
没有类别代码 3。
解决方法
提交错误报告并执行,直到修复发布为止,
\usepackage{algorithm2e}
\makeatletter
\begingroup
\catcode`\Q=3
\catcode`\T=3
\long\gdef\ifArgumentEmpty#1{%
\long\def\@tempa##1##2Q##3##4##5T{##4}%
\long\edef\@tempa{\@tempa#1QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T}%
\@tempa
}
\endgroup
\makeatother
一个更简单的解决方法是
\usepackage{algorithm2e}
\usepackage{etoolbox}
\let\ifArgumentEmpty\ifblank
向软件包开发人员建议一个可能更好的修复方法:
\makeatletter
\begingroup
\catcode`\Q=3
\catcode`\T=3
\long\gdef\ALGOCF@argemptyaux#1#2Q#3#4#5T{#4}
\long\gdef\ifArgumentEmpty#1{%
\begingroup\long\edef\@tempa{\endgroup
\ALGOCF@argemptyaux#1QQ{\noexpand\@secondoftwo}{\noexpand\@firstoftwo}T%
}\@tempa
}
\endgroup
\makeatother
辅助宏定义一次即可,因为它总是会得到相同的定义;
\begingroup\edef\@tempa{\endgroup...}\@tempa
技巧,\@tempa
只是临时设置,不会污染哈希内存。无需全局定义。