答案这问题详细解释了什么是保护,所以我对此并不感到疑惑。我的问题是为什么某个命令定义expl3
没有给出受保护的命令。
考虑这个 LaTeX2e 示例:
\documentclass{article}
\DeclareRobustCommand\foo[1]{#1}
\DeclareRobustCommand\?{??}
\expandafter\DeclareRobustCommand\expandafter\-\expandafter{\-}
\begin{document}
\tableofcontents
% this is <jobname>.toc:
% \contentsline {section}{\numberline {1}\foo {bar}}{1}
% \contentsline {section}{\numberline {2}foo\?}{1}
% \contentsline {section}{\numberline {3}foo\-bar}{1}
\section{\foo{bar}}
\section{foo\?}
\section{foo\-bar}
\end{document}
一切如预期般进展。
但是,当我尝试对未受保护的对象expl3
执行相同操作时:\-
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_protected:Npn \foo #1 { #1 } % works
\cs_new_protected:Npn \? { ?? } % works
\exp_args:NNo \cs_set_protected:Npn \- { \- } % does not work
\ExplSyntaxOff
\begin{document}
\tableofcontents
% this is <jobname>.toc:
% \contentsline {section}{\numberline {1}\foo {bar}}{1}
% \contentsline {section}{\numberline {2}foo\?}{1}
% \contentsline {section}{\numberline {3}foo\discretionary {-}{}{}bar}{1}
% \contentsline {section}{\numberline {4}foo\-bar}{1}
\section{\foo{bar}}
\section{foo\?}
\section{foo\-bar}
\section{foo\protect\-bar}
\end{document}
我做错了什么吗?为什么没有\exp_args:NNo \cs_set_protected:Npn \- { \- }
得到想要的结果?我能找到这种行为的唯一命令是\-
。是我看得不够仔细还是有什么特别之处\-
?
答案1
你被 LaTeX2e 而不是 LaTeX2e 所困扰expl3
!你使用的重新定义是正确的,如果你这样做,你就会明白这一点\show\-
:
> \-=\protected\long macro:
->\discretionary {-}{}{}.
然而,LaTeX2e\-
在输出例程中重新定义,这是.toc
创建条目的地方:
\@arrayparboxrestore ->\let \if@nobreak \iffalse \let \if@noskipsec \iffalse \l
et \par \@@par \let \-\@dischyph \let \'\@acci \let \`\@accii \let \=\@acciii \
parindent \z@ \parskip \z@skip \everypar {}\linewidth \hsize \@totalleftmargin
\z@ \leftskip \z@skip \rightskip \z@skip \@rightskip \z@skip \parfillskip \@flu
shglue \lineskip \normallineskip \baselineskip \normalbaselineskip \sloppy
{\let}
{reassigning \if@nobreak=\iffalse}
{\let}
{reassigning \if@noskipsec=\iffalse}
{\let}
{reassigning \par=\par}
{\let}
{changing \-=\protected\long macro:->\discretionary {-}{}{}}
{into \-=macro:->\discretionary {-}{}{}}
...
因此,您可能想知道为什么我们看到受保护命令和 LaTeX2e“强大”命令的行为之间存在差异:毕竟,输出例程都忽略了这两个命令!这取决于不同的保护如何工作。使用 LaTeX3 方法,这取决于引擎,因此每次\edef
应用或类似命令时\-
,它都保持不变。但是,LaTeX2e 会删除保护。
另一方面,LaTeX2e 的强健机制会导致内部\-
变成。这意味着,即使我们稍后更改 的定义,保护仍然“有效”。\protect\-
\edef
\-
.toc
您可以看到 TeX 向when写入的内容\tracingall
。借助 LaTeX2e 的强大机制:
\write->\@writefile{toc}{\protect \contentsline {section}{\protect \numberline
{1}foo\protect \-bar}{\thepage }}
但使用 LaTeX3 的原生引擎系统
\write->\@writefile{toc}{\protect \contentsline {section}{\protect \numberline
{1}foo\-bar}{\thepage }}
正如 egreg 已经评论的那样,目前最好的解决方案是\@dischyph
通过将 engine-protected 设置为 来使其相等\-
。 (当然,从长远来看,LaTeX3 格式将使所有内容受到保护或可扩展,这种问题应该会消失。)
顺便说一下,我会用
\cs_set_protected_nopar:Npx \- { \exp_not:o { \- } }
答案2
LaTeX 在输出过程中会执行一些操作\@arrayparboxrestore
,其中包括:
\-\@dischyph
其中\@dischyph
,由内核定义为
560 \def\-{\discretionary{-}{}{}}
561 \let\@dischyph=\-
(我留下了行号)。这意味着当文件.aux
被写出时,\-
它再次具有重新定义之前的值(当然不受保护)。\DeclareRobustCommand
传递给.aux
文件的内容是不是 \-
,但有所不同(事实上\protect\-
,由于\protect
是\noexpand
,所以变为未展开的\-
)。因此问题不明显。
解决方案:添加
\makeatletter
\let\@dischyph\-
\makeatother
重新定义之后\-
。