用任意符号替换数字

用任意符号替换数字

我想编写一些宏,用以前定义的符号或宏替换其参数中的所有数字。

我设想的是

\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}

相关内容