如果\lccode
不改变类别代码,那么不应该根据小写字母技巧也适用于数字吗?那么,适用于任何字符吗?
\documentclass{article}
\usepackage{fontspec}% xelatex
\long\def\clownaround#1{% based on https://tex.stackexchange.com/a/219497/13552
\begingroup% only needed to limit scope of formatting macros
\ttfamily%
\begingroup\lccode`~=`0\lowercase{\endgroup\def~}{YOUVEBEENPSYCHED0}%
\begingroup\lccode126=48\lowercase{\endgroup\def~}{YOUVEBEENPSYCHED0} % equivalent of prev line
\begingroup\lccode`~=`/\lowercase{\endgroup\def~}{YOUVEBEENFOOLED/}%
\begingroup\lccode`~=`a\lowercase{\endgroup\def~}{YOUVEBEENDUPEDa}%
\catcode`/=\active\catcode`.=\active% what does this do?
\scantokens{#1\noexpand}%
\endgroup%
}
\begin{document}
\clownaround{01/a}% Expected output: YOUVEBEENPSYCHED01YOUVEBEENFOOLED/YOUVEBEENDUPEDa
\end{document}
答案1
为了回答提出的问题,“基于\lowercase
技巧的代码”做适用于数字或任何字符。问题中有几个不同之处;分别介绍它们可能有助于澄清问题:
- 您可以为任何字符给出定义,但仅当 TeX 遇到该字符是活动字符时才使用该定义。
为字符赋予定义只是将该定义存储在某个表中。当 TeX 遇到字符时,如果它的类别代码为 11(“字母”)或 12(“其他字符”),TeX 只会排版该字符,如果它的类别代码为 3(“数学移位”,如$
),TeX 会进入或退出数学模式,等等。只有当字符的类别代码为 13(“活动字符”)时,TeX 才会查找该字符的定义并使用它。
这是问题中提出的主要内容,这里有一个更简单的例子:
\documentclass{article}
\begin{document}
\catcode`Z=13 % Makes Z an active character
\defZ{Duck} % Gives Z the definition "Duck"
\catcode`Z=11 % Makes Z a letter again
Z Z Goose % Output: Z Z Goose
\catcode`Z=13 % Makes Z an active character
Z Z Goose % Output: Duck Duck Goose
\end{document}
- 在这个例子中,技巧
\lowercase
只是一种避免设置 catcode 并返回的方法。(因为~
inside\lowercase
导致 token 的 catcode 为~
,但实际字符为 的小写版本~
。)
例如,下面已经说明了问题的许多特征,而没有群体和的复杂化\scantokens
:
\documentclass{article}
\begin{document}
\ttfamily
\lccode`~=`0 \lowercase{\def~}{YOUVEBEENPSYCHED0} % Gives the character 0 the definition "YOUVEBEENPSYCHED0"
\lccode`~=`/ \lowercase{\def~}{YOUVEBEENFOOLED/} % Gives the character / the definition "YOUVEBEENFOOLED/"
\lccode`~=`a \lowercase{\def~}{YOUVEBEENDUPEDa} % Gives the character a the definition "YOUVEBEENDUPEDa"
\catcode`/=\active % Makes the character / active (so that / will be replaced by its definition)
\catcode`0=\active % Makes the character 0 active (so that 0 will be replaced by its definition)
01/a % Output: YOUVEBEENPSYCHED01YOUVEBEENFOOLED/a
\end{document}
请注意,这里我们给了角色a
一个定义,但它从未使用过(因为角色的 catcode 不为\active
= 13)。
\catcode
如果我们想将设置或的效果限制\lccode
在某个区域,那时我们就需要\begingroup
和的进一步复杂化\endgroup
(如问题中所示)。
当字符a
处于活动状态时,\relax
将被解释为\rel
后跟a
后跟x
,因此 TeX 会抱怨未定义的控制序列\rel
。 (\scantokens
有趣的是,这不会导致错误,而只是做了错误的事情。)所以我们需要小心并将其括在一个组中:在前面刚刚提到的文档中,在之前添加以下内容\end{document}
:
% We need to be more careful with the character 'a', because
% otherwise \relax will be interpreted as \rel, then a, then x.
\def\clownaround{
\begingroup
\catcode`a=\active
\scantokens{01/a}
\endgroup
}
\clownaround
0
这里使用了、/
和的定义a
。\begingroup
和\endgroup
限制了 的范围,\catcode`a = 13
以便 等\relax
以后仍能起作用。 和\scantokens
的使用使得“01/a”使用该点(当宏\clownaround
展开并遇到时)的 catcode 进行扫描,而不是使用定义\scantokens
宏时的 catcode 。\clownaround
问题中的另一个技巧\begingroup
是\endgroup
\begingroup\lccode`~=`0\lowercase{\endgroup\def~}{YOUVEBEENPSYCHED0}
这尽可能地限制了的范围\lccode
,以防我们稍后要求的小写版本,~
而0
实际上我们得到的是其他版本。
- 这里不需要末尾
\noexpand
的\scantokens
;它只是\scantokens
为了避免出现空格而使用的一般做法。
答案2
当你重新扫描材料时,e-TeX 会应用目前活跃类别代码。在本例中,除受以下行影响的两个类别代码外,均适用“正常”类别代码
\catcode`/=\active\catcode`.=\active
因此重新扫描后0
,ETC。作为“其他”角色,而\lowercase
“技巧”已经定义了一个积极的 0
扩展为某物没有区别。你需要让你感兴趣的每个角色都“活跃”:
\catcode`0=\active
\catcode`a=\active
% Others
这引出了一个简单的例子
\documentclass{article}
\long\def\clownaround#1{% based on https://tex.stackexchange.com/a/219497/13552
\begingroup% only needed to limit scope of formatting macros
\ttfamily%
\begingroup\lccode`~=`0\lowercase{\endgroup\def~}{YOUVEBEENPSYCHED0}%
\begingroup\lccode`~=`/\lowercase{\endgroup\def~}{YOUVEBEENFOOLED/}%
\begingroup\lccode`~=`a\lowercase{\endgroup\def~}{YOUVEBEENDUPEDa}%
\catcode`/=\active
\catcode`\0=\active
\catcode`\a=\active
\endlinechar=-1 %
\scantokens{#1}%
\endgroup%
}
\begin{document}
\clownaround{01/a}% Expected output: YOUVEBEENPSYCHED1YOUVEBEENFOOLEDYOUVEBEENDUPED
\end{document}