健壮命令不会扩展为 \input 参数

健壮命令不会扩展为 \input 参数

我确实需要一些帮助——我已经随意使用 LaTeX 好几年了,但很少深入研究细节或问题,我无法弄清楚这一点。

问题

我正在处理.cls我的组织给我的​​一个文件,其中有一行(可能)有问题。它定义了一个宏,用于存储输入点大小的第二位数字,然后使用该数字输入文件.clo。配对的 MWE 如下:

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}

\RequirePackage{etoolbox}
\newrobustcmd\@ptsize{}

\DeclareOption{10pt}{\renewrobustcmd\@ptsize{0}}
\DeclareOption{11pt}{\renewrobustcmd\@ptsize{1}}
\DeclareOption{12pt}{\renewrobustcmd\@ptsize{2}}

\ExecuteOptions{11pt}
\ProcessOptions
\input{size1\@ptsize.clo}

我还创建了一个 MWE.tex文件来编译:

\documentclass[11pt]{mwe}

\begin{document}
    
\end{document}

但是,当我使用(在 VSCode 中使用 LaTeX Workshop)编译它时latexmk -synctex=1 -interaction=nonstopmode -file-line-error -pdf -outdir=%OUTDIR% %DOC%,我收到此日志文件,其中有一条消息说

`File `[email protected]' not found`

日志显示:

This is pdfTeX, Version 3.14159265-2.6-1.40.21 (MiKTeX 20.11) (preloaded format=pdflatex 2020.11.3)  3 NOV 2020 08:57
entering extended mode
**"path/to/mwe/mwe.tex"
("path/to/mwe/mwe.tex"
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> ("path/to\mwe\mwe.cls" <-- In case it matters, these slashes
Document Class: mwe                                                              really do switch directions
(path\to\tex/latex/etoolbox\etoolbox.sty                                     <-- Here as well
Package: etoolbox 2020/10/05 v2.5k e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count175
)

! LaTeX Error: File `[email protected]' not found.

Type X to quit or <RETURN> to proceed,
or enter new name. (Default extension: clo)

Enter file name: 

潜在解决方案

事情是这样的:如果我更改文件.cls,使其通过和而不是通过和来@ptsize定义,那么上面的 MWE文件就可以正常工作,并生成一个空白(两页)PDF。\newcommand\renewcommand\newrobustcmd\renewrobustcmd.tex

有人能解释一下为什么会发生这种情况吗?(据我所知,这个.cls文件对我组织中的其他人来说运行良好),以及 b)解决此问题的最佳实践方法是什么?提前谢谢您!

答案1

在此示例代码中可以看到行为的差异:

\makeatletter
\protected\def\@ptsize{1}
\input{size1\@ptsize.clo}
\stop

以前可以输入size11.clo,但是从 2020-10-01 LaTeX 版本开始,它不再能输入 ,而是出现错误:

! LaTeX Error: File `[email protected]' not found.

Type X to quit or <RETURN> to proceed,
or enter new name. (Default extension: clo)

Enter file name:

这是对 LaTeX 文件名解析机制的一次刻意改变。它被一个更强大的解析器所取代,该解析器不会扩展受保护的宏(以及其他几个优点)。新解析器的行为与强大的宏有关:这些不能在仅扩展的上下文中工作,因为它们无论如何都会崩溃( 寻找 例子 大约),因此不扩大它们是合理之举。

贵组织中的类文件滥用了强大的命令来存储某些数据(我们通常称之为“令牌列表”)。此类数据通常必须始终可供其他宏使用,因此必须扩展,因此无法保持强大/受保护。如果您可以编辑类文件,则正确的做法是将其替换\(re)newrobustcmd\(re)newcommand

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}

\RequirePackage{etoolbox}
\newcommand\@ptsize{}

\DeclareOption{10pt}{\renewcommand\@ptsize{0}}
\DeclareOption{11pt}{\renewcommand\@ptsize{1}}
\DeclareOption{12pt}{\renewcommand\@ptsize{2}}

\ExecuteOptions{11pt}
\ProcessOptions
\input{size1\@ptsize.clo}

根据记录,错误消息

! LaTeX Error: File `[email protected]' not found.

看起来像那样,因为文件名解析器与 一起工作\escapechar=-1,然后\@ptsize被 击中\string并变成@ptsize

答案2

如果由于某些不为人知的原因,必须坚持在强大的宏中存储可检索的数据,那么您可以使用一些\expandafter/ \romannumeral/argument-exchanging-trickery 自己触发扩展并按正确的顺序放置标记:

文件mwe.cls

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}

\RequirePackage{etoolbox}
\newrobustcmd\@ptsize{}

\DeclareOption{10pt}{\renewrobustcmd\@ptsize{0}}
\DeclareOption{11pt}{\renewrobustcmd\@ptsize{1}}
\DeclareOption{12pt}{\renewrobustcmd\@ptsize{2}}

\newcommand\exchangeargs[2]{#2#1}

\ExecuteOptions{11pt}
\ProcessOptions
% It is not relied on \input expanding and putting into correct order
% tokens of its argument.
% Instead \romannumeral-expansion brings all tokens into
% correct order before \input and \input's filename-parsing 
% come into action.
% (This way things might sustain more changes to \input's 
% filename-parsing.)
\expandafter\input\expandafter{%
  \romannumeral
  \expandafter\exchangeargs\expandafter{\@ptsize}{\z@ size1}.clo%
}

在我的系统上编译一个文件test.tex

\documentclass{mwe}
\stop

产生这个控制台输出:

$ pdflatex test.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> (./mwe.cls
Document Class: mwe 
(/usr/local/texlive/2020/texmf-dist/tex/latex/etoolbox/etoolbox.sty)
(/usr/local/texlive/2020/texmf-dist/tex/latex/base/size11.clo)) )
No pages of output.
Transcript written on test.log.

和这个文件test.log

This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex 2020.11.23)  4 DEC 2020 19:47
entering extended mode
 restricted \write18 enabled.
 %&-line parsing enabled.
**test.tex
(./test.tex
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> (./mwe.cls
Document Class: mwe 
(/usr/local/texlive/2020/texmf-dist/tex/latex/etoolbox/etoolbox.sty
Package: etoolbox 2020/10/05 v2.5k e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count175
)
(/usr/local/texlive/2020/texmf-dist/tex/latex/base/size11.clo
File: size11.clo 2020/04/10 v1.4m Standard LaTeX file (size option)
)) ) 
Here is how much of TeX's memory you used:
 364 strings out of 479485
 4393 string characters out of 5871962
 273140 words of memory out of 5000000
 17462 multiletter control sequences out of 15000+600000
 535388 words of font info for 30 fonts, out of 8000000 for 9000
 1141 hyphenation exceptions out of 8191
 52i,1n,59p,208b,36s stack positions out of 5000i,500n,10000p,200000b,80000s

No pages of output.
PDF statistics:
 0 PDF objects out of 1000 (max. 8388607)
 0 named destinations out of 1000 (max. 500000)
 1 words of extra memory for PDF output out of 10000 (max. 10000000)

对于您的问题:

a)解释为什么会发生这种情况(据我所知,这个 .cls 文件对我组织中的其他人来说运行良好)

LaTeX 2ε 内核进行了重大更改。最近的一项更改是,在\input{...}稳健宏的参数内不进行扩展。

这些变化既好又烦人:它们很好,因为对于很多事情来说,它们现在的工作方式对我来说似乎更加严格。它们很烦人,因为我必须再次查看代码并习惯它。;-)

您所在组织中的其他人可能不使用较新版本的 LaTeX 2ε 内核,因此较新版本的 LaTeX 2ε 内核引入的更改不会影响他们机器上的运行方式。

b) 解决这个问题的最佳实践方法是什么?

我不知道这些是不是“最佳实践”,但由于过去两年发生了如此多的变化,我已经不再依赖 LaTeX 2ε-kernel 宏来按照我二十多年来习惯的方式工作。;-)

特别是我不再像两天前那样依赖其他人维护的代码进行扩展,因此我经常让我自己的代码完成所有的扩展工作,然后再将事物作为参数交给其他人的宏。

我不会这样做,因为我会对变化和创新感到不满意。

我这样做是为了使我自己的代码与尽可能多的不同 LaTeX 2ε 版本兼容。

相关内容