![意外的换行符(catcode 魔法)](https://linux22.com/image/442350/%E6%84%8F%E5%A4%96%E7%9A%84%E6%8D%A2%E8%A1%8C%E7%AC%A6%EF%BC%88catcode%20%E9%AD%94%E6%B3%95%EF%BC%89.png)
我正在玩 Tex catcodes 和 hboxes。以下代码应产生三行输出:
A...1...
B...2...
C...3...
A
然而,由于某种原因,它在和之间出现了换行符...1...
,但我不知道为什么。
以下是代码:
\def\changeCatcodes{
\catcode`A=13
\catcode`B=13
\catcode`C=13
}
\begingroup
\changeCatcodes
\gdefA{\argtohbox{\string A}}
\gdefB{\argtohbox{\string B}}
\gdefC{\argtohbox{\string C}}
\endgroup
\gdef\argtohbox#1{\hbox to 20pt{#1}}
\gdef\newstring{\penalty-10000}
\catcode`\^^M=13 % one for reading macro definition
\def\specialenv{%
\begingroup%
\parindent0pt%
\catcode`\^^M=13 % ... and one for actually changing it when it is executed
\changeCatcodes%
\let^^M\newstring%
}
\catcode`\^^M=5 % return catcode back
\def\endspecialenv{\endgroup}
\specialenv
A...1...
B...2...
C...3...
\endspecialenv
\end
答案1
答案2
当 TeX 处于垂直模式时,它会在它们之间堆叠盒子(可能添加行间粘连)并添加随之而来的其他垂直材料。
如果您\hbox{...}
在 TeX 处于垂直模式时进行贡献,它只会遵循其性质并将其与已经贡献的材料一起堆叠。
某些 token 会导致垂直模式被搁置,水平模式开始。水平模式的目的是准备一个或多个框,以便在返回垂直模式时进行贡献(这由以下情况触发:\par
,可能会隐式添加)。这些 token 中有不是 \hbox
,如上所述。但是,如果\hbox
在水平模式下发现,则在此模式下会贡献。
一个字符(在您的情况下是第一个句点)导致水平模式启动。它将在之后结束,\endspecialenv
或者更准确地说,通过\end
隐式提供的结束\par
。
您将获得相同的输出
\parindent=0pt
\hbox to 20pt{A}...1...\break
\hbox to 20pt{B}...2...\break
\hbox to 20pt{C}...3...\break
\end
以及几条Underfull \hbox
消息:
Underfull \hbox (badness 10000) detected at line 3
\tenrm A
Underfull \hbox (badness 10000) detected at line 4
\tenrm B
Underfull \hbox (badness 10000) detected at line 5
\tenrm C
Underfull \hbox (badness 10000) in paragraph at lines 3--6
[]\tenrm ...1...
Underfull \hbox (badness 10000) in paragraph at lines 3--6
[]\tenrm ...2...
Underfull \hbox (badness 10000) in paragraph at lines 3--6
[]\tenrm ...3...
Underfull \hbox (badness 10000) in paragraph at lines 3--6
固定代码:
\def\changeCatcodes{
\catcode`A=13
\catcode`B=13
\catcode`C=13
}
\begingroup
\changeCatcodes
\gdef A{\argtohbox{\string A}}
\gdef B{\argtohbox{\string B}}
\gdef C{\argtohbox{\string C}}
\endgroup
\def\argtohbox#1{\hbox to 20pt{#1\hss}}
\def\newstring{\hfil\penalty-10000 }
\catcode`\^^M=13 % one for reading macro definition
\def\specialenv{%
\begingroup%
\parindent0pt%
\catcode`\^^M=13 % ... and one for actually changing it when it is executed
\changeCatcodes%
\let^^M\newstring%
\leavevmode%
}
\catcode`\^^M=5 % return catcode back
\def\endspecialenv{\unpenalty\endgroup}
\specialenv
A...1...
B...2...
C...3...
\endspecialenv
\end
\hss
提供可拉伸的胶水,避免盒子不够满\hfil
避免\penalty-10000
线路未满\leavevmode
启动水平模式\unpenalty
删除最后一行末尾的惩罚- 注意后面的空格
-10000
可以避免以下标记可能不合时宜地扩展
您可能会喜欢研究这种定义活跃角色的不同方法:
\def\activedef#1{%
\begingroup\lccode`~=`#1\lowercase{\endgroup\def~}%
}
\activedef A{\argtohbox{A}}
\activedef B{\argtohbox{B}}
\activedef C{\argtohbox{C}}
这些定义没有必要,\global
也没有必要开个小组来发布\changeCatcodes
。也没有\string
。