我需要 (1) 计算数字中的位数(或计算单词中的字母数),以及 (2) 检索这些数字中的任意一个(或这些字母中的任意一个)。此外,还需要满足以下条件:expl3
不应使用以及非由 LaTeX 团队创作/维护的软件包。
\def\zCountDigits#1%
{% COUNT DIGITS OF #1
}
\def\zGetDigit#1#2%
{% GET DIGIT OF #1 AT INDEX #2
}
答案1
人们总是可以采用现有的代码并重新编写。在这里,我使用了一些想法,expl3
但略微简化了(以牺牲一点鲁棒性为代价)
\def\zCountDigits#1{%
\number\numexpr0\zCountDigitsAux#1\zCountDigitsEnd\relax
}
\def\zCountDigitsAux#1{%
\ifx\zCountDigitsEnd#1\else+1\expandafter\zCountDigitsAux\fi
}
\def\zCountDigitsEnd{\zCountDigitsEnd}
\zCountDigits{}
\zCountDigits{123}
\zCountDigits{abC}
\def\zGetDigit#1#2{%
\zGetDigitLoop{1}{#2}#1\zGetDigitEnd
}
\def\zGetDigitLoop#1#2#3{%
\ifx\zGetDigitEnd#3\else
\ifnum #1 = #2 %
\expandafter\expandafter\expandafter\zGetDigitCleanup
\expandafter\expandafter\expandafter#3%
\else
\zGetDigitLoopStep{#1}{#2}%
\fi
\fi
}
\def\zGetDigitCleanup#1#2\zGetDigitEnd{#1}
\def\zGetDigitLoopStep#1#2\fi\fi{\fi\fi
\expandafter\zGetDigitLoop\expandafter{\number\numexpr#1 + 1\relax}{#2}%
}
\def\zGetDigitEnd{\zGetDigitEnd}
\zGetDigit{abc}{1}
\zGetDigit{abc}{3}
\zGetDigit{abc}{4}
\zGetDigit{abc}{-2}
\bye
(我不能 100% 确定你是否需要空间处理、括号组保留,ETC。:我采用了简单的方法,但它们也可以包括在内。
循环的工作方式是\zCountDigitsAux
每次抓取一个标记:如果你看一下设置,就会发现 中没有括号#1
。\zCountDigits
因此,\ifx\zCountDigitsEnd#1
是将一个标记与结束标记进行比较。我使用了私有的“循环结束”标记,而不是说\relax
。这是为了确保我们仍然可以计算包含 的输入序列\relax
:这里的计数方法不仅适用于字符标记,还适用于宏、\chardef
标记、ETC。
假设循环尚未完成,我们插入+1
然后需要关闭条件。\zCountDigitsAux
宏需要查看输入流中的下一个内容,我们需要避免打开越来越多的条件级别。因此我使用
\expandafter\zCountDigitsAux\fi
。这会扩展\fi
,结束条件,在\zCountDigitsAux
扩展之前。(如果没有这个,\zCountDigitsAux
会抓住\fi
,我们会用完堆栈。)\zCountDigitsAux
这里没有传递任何参数,因为其余的原始参数\zCountDigits
仍在输入流中。
答案2
以下解决方案根本不使用任何包,因此不会违反禁止使用“非由 LaTeX 团队创作/维护”的包的规定。(另外:我不知道“LaTeX 团队”的成员是谁——或者甚至不知道是否有这样的团队。)
由于您在示例中使用的是\def
而不是\newcommand
,我认为您主要对“纯 TeX”解决方案感兴趣。因此,下面显示的代码使用的是 LuaTeX ,而不是 LuaLaTeX。代码提供了两个宏,\zCountChars
和\zGetChar
。宏使用“primitive”命令\directlua
和内置的 LuaTeX 函数tex.sprint
、string.len
和string.sub
。
\def\zCountChars#1{\directlua{tex.sprint(string.len("#1"))}}
\def\zGetChar#1#2{\directlua{tex.sprint(string.sub("#1",#2,#2))}}
\zCountChars{1066}, \zCountChars{123abc}.
\zGetChar{6789}{2}, \zGetChar{123abc}{-2}.
\bye
请注意,可以使用负数作为 的第二个参数\zGetChar
。在这种情况下,计数开始从最后字符串/数字,而不是从头开始。