我想编写一些宏,用以前定义的符号或宏替换其参数中的所有数字。
我设想的是
\overrideDigits{1234567890}
应该扩展为类似
\one\two\three\four\five\six\seven\eight\nine\zero
通过重写这些宏来定义输出内容。或者更高级的版本是
\overrideDigits{1234567890 + \otherMacro}
应该导致
\one\two\three\four\five\six\seven\eight\nine\zero + \otherMacro
我认为最简单的解决方案(对于更简单的版本)是覆盖宏中的数字的 catcode。然而,到目前为止,我所有的尝试都以错误消息告终
Missing control sequence inserted.
<inserted text>
\inaccessible
l.59 \overrideDigits{1234567890}
?
我已经从简单的尝试“进步”到了这个
\def\overrideDigits#1{%
\begingroup
\catcode`0=\active
\def0{\zero}
% and so on for the other digits
\scantokens\expandafter{#1\empty}%
\endgroup}
这是我改编的这个答案。
- 我究竟做错了什么?
- 难道不可能用
\def
数字表示吗? - 有没有更好的方法来实现这个目标?
答案1
在我看来,更改类别代码是最糟糕的方法。
这是一个简单的实现xparse
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\overrideDigits}{m}
{
\tl_map_inline:nn { #1 }
{
\nobody_digit:n { ##1 }
}
}
\cs_new:Npn \nobody_digit:n #1
{
\str_case:nn { #1 }
{
{0}{Zero}
{1}{One}
{2}{Two}
{3}{Three}
{4}{Four}
{5}{Five}
{6}{Six}
{7}{Seven}
{8}{Eight}
{9}{Nine}
}
}
\ExplSyntaxOff
\begin{document}
\overrideDigits{12345}
\overrideDigits{67890}
\end{document}
输入按字符进行映射,并将每个数字替换为您选择的任何数字(回想一下,需要输入空格,如~
定义主体中所示\nobody_digit:n
。
一个“经典”的实现:
\documentclass{article}
\makeatletter
\newcommand{\overrideDigits}[1]{%
\@tfor\next:=#1\do{\csname digit\next subs\endcsname}%
}
\@namedef{digit0subs}{Zero}
\@namedef{digit1subs}{One}
\@namedef{digit2subs}{Two}
\@namedef{digit3subs}{Three}
\@namedef{digit4subs}{Four}
\@namedef{digit5subs}{Five}
\@namedef{digit6subs}{Six}
\@namedef{digit7subs}{Seven}
\@namedef{digit8subs}{Eight}
\@namedef{digit9subs}{Nine}
\makeatother
\begin{document}
\overrideDigits{12345}
\overrideDigits{67890}
\end{document}
另一种expl3
实现方式是使用不同的数字渲染。您定义命名列表,每个数字选择相应的项目。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\overrideDigits}{O{default}m}
{
\tl_map_inline:nn { #2 }
{
\clist_item:cn { l_nobody_digits_#1_clist } { ##1 + 1 }
}
}
\NewDocumentCommand{\definedigits}{mm}
{
\clist_clear_new:c { l_nobody_digits_#1_clist }
\clist_set:cn { l_nobody_digits_#1_clist } { #2 }
}
\ExplSyntaxOff
\definedigits{default}{0,1,2,3,4,5,6,7,8,9}
\definedigits{names}{
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine
}
\definedigits{greek}{
\ensuremath{\alpha},
\ensuremath{\beta},
\ensuremath{\gamma},
\ensuremath{\delta},
\ensuremath{\varepsilon},
\ensuremath{\zeta},
\ensuremath{\eta},
\ensuremath{\vartheta},
\ensuremath{\iota},
\ensuremath{\kappa}
}
\begin{document}
\overrideDigits{1234567890}
\overrideDigits[names]{0123456789}
\overrideDigits[greek]{0123456789}
\end{document}
为什么你的尝试会失败?主要是因为当你尝试执行时\def0
,它不活跃,因为它已被吸收到不活跃时0
的替换文本中。\overrideDigits
一个可能的解决方案是
\def\overrideDigits#1{%
\begingroup
\catcode`0=\active
\begingroup\lccode`~=`0 \lowercase{\endgroup\let~}{\zero}%
% and so on for the other digits
\scantokens\expandafter{#1\empty}%
\endgroup
}
另一种可能性是
\begingroup
\catcode`0=\active \catcode`1=\active
\catcode`2=\active \catcode`3=\active
\catcode`4=\active \catcode`5=\active
\catcode`6=\active \catcode`7=\active
\catcode`8=\active \catcode`9=\active
\gdef\overrideDigits#1{%
\catcode`0=\active \catcode`1=\active
\catcode`2=\active \catcode`3=\active
\catcode`4=\active \catcode`5=\active
\catcode`6=\active \catcode`7=\active
\catcode`8=\active \catcode`9=\active
\let0\zero \let1\one \let2\two \let3\three \let4\four
\let5\five \let6\six \let7\seven \let8\eight \let9\nine
\scantokens{#1\empty}%
}
\endgroup
答案2
这是一个基于 LuaLaTeX 的解决方案。我故意没有优化 Lua 端的代码,这样即使你对 Lua 一点都不熟悉,也可以轻松修改每个替换操作的输出。
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode} % for "luacode" environment and "\luastring" macro
%% Lua-side code
\begin{luacode}
function override_digits ( s )
-- replace each digit with a macro
s = string.gsub ( s, "0", "\\zero")
s = string.gsub ( s, "1", "\\one")
s = string.gsub ( s, "2", "\\two")
s = string.gsub ( s, "3", "\\three")
s = string.gsub ( s, "4", "\\four")
s = string.gsub ( s, "5", "\\five")
s = string.gsub ( s, "6", "\\six")
s = string.gsub ( s, "7", "\\seven")
s = string.gsub ( s, "8", "\\eight")
s = string.gsub ( s, "9", "\\nine")
tex.sprint ( s )
end
\end{luacode}
%% TeX-side code
\newcommand\overrideDigits[1]{%
\directlua{ override_digits ( \luastring{#1} )}}
%% set up the macros \zero, \one, etc
\def\zero{0}
\def\one{9}
\def\two{8}
\def\three{7}
\def\four{6}
\def\five{5}
\def\six{4}
\def\seven{3}
\def\eight{2}
\def\nine{1}
\def\otherMacro{9999}
\begin{document}
\overrideDigits{abc123}
\directlua{tex.sprint(\overrideDigits{4321} + \otherMacro)}
\end{document}