在我正在编写的 documentclass 中,用户将输入一个整数,例如,\lessonnumber
一个可能带有多个前导零的整数,例如 4。04
在文档中的某些地方,我需要完整形式(04
),而在其他地方,我只需要通用形式(4
)。我该如何实现这一点?
答案1
我引入了\stripzero
,它可以与括号内的参数一起使用,也可以与括号外的参数一起使用。该参数可以是可扩展的宏。
宏以递归方式工作。 的定义\stripzero
首先扩展其参数,这是允许对诸如 之类的宏进行操作所必需的\lessonnumber
。 参数扩展后,它会调用递归例程,将下一个标记与 进行比较0
。 如果不是零,它会打印该标记并停止。 如果标记是0
,它会忽略/丢弃它,然后再次调用自身以查看下一个标记。
避免宏将 视为\else
其下一个参数的诀窍是将 视为\expandafter
宏,以便吸收\else
。如果我将 递归调用\stripzero
(而不是\stripzerohelp
),则\expandafter
就没有必要了。但是,双宏递归也不是最有效的,因此我让递归例程直接调用自身,同时保留\expandafter
。
\documentclass{article}
\def\stripzero#1{\expandafter\stripzerohelp#1}
\def\stripzerohelp#1{\ifx 0#1\expandafter\stripzerohelp\else#1\fi}
\begin{document}
\stripzero{4}
\stripzero 04
\stripzero 004
\stripzero{004}
\def\lessonnumber{00056}
\stripzero\lessonnumber
\stripzero{\lessonnumber}
\end{document}
Marc 提出了一个有趣的问题:如何处理纯零参数。上面的 MWE 将它们全部删除。但是,这可能不是我们想要的。0
如果参数是一串零,则可能需要打印出单个零。
因此,我提供了以下替代实现,用于检查第一个非零标记。如果是数字,则其行为与以前相同。但如果后续标记不是数字,则它会断定该数字是一串纯零,并输出单个0
。
\documentclass{article}
\def\stripzero#1{\expandafter\stripzerohelp#1}
\def\stripzerohelp#1{\ifx 0#1\expandafter\stripzerohelp\else\checkrange{#1}#1\fi}
\def\checkrange#1{\ifx1#1\else\ifx2#1\else\ifx3#1\else\ifx4#1\else\ifx5#1\else%
\ifx6#1\else\ifx7#1\else\ifx8#1\else\ifx9#1\else0\fi\fi\fi\fi\fi\fi\fi\fi\fi}
\begin{document}
\stripzero{4}
\stripzero 04
\stripzero 004
\stripzero{004}
\def\lessonnumber{00056}
\stripzero\lessonnumber
\stripzero{\lessonnumber}
\def\lessonnumber{000}
\stripzero{\lessonnumber}xyz
\stripzero\lessonnumber xyz
$\stripzero\lessonnumber\vec{x}$
\end{document}
答案2
小于 2 31 -1 的数字
如果该数字符合 TeX 的数字范围,则可以用 vanilla TeX 的方法来对该数字进行规范化\number
:
\number\lessonnumber\relax
末尾\relax
的 (或空的花括号对)可防止 TeX 在 之后寻找更多数字\lessonnumber
。可扩展版本必须使用不同的技巧:
\makeatletter
\newcommand*{\normalizedlessonnumber}{%
\expandafter\@firstofone\expandafter{\number\lessonnumber}%
}
\makeatother
然后,结束的花括号将作为 TeX 数字扫描仪的阻止器,并且花括号将作为 的参数括号消失\@firstofone
。
可扩展的 e-TeX 版本附加了对某些算术运算的支持:
\the\numexpr(\lessonnumber)\relax
无限整数
\bigintcalcNum
可以通过包对无限整数进行可扩展的规范化bigintcalc
:
\bigintcalcNum{\lessonnumber}
添加前导零
如果数字符合 TeX 的整数范围,则以下宏\padnum
会添加前导零(取自我的回答对此问题)。
\makeatletter
\newcommand{\padnum}[2]{%
\ifnum#1>1 \ifnum#2<10 0\fi
\ifnum#1>2 \ifnum#2<100 0\fi
\ifnum#1>3 \ifnum#2<1000 0\fi
\ifnum#1>4 \ifnum#2<10000 0\fi
\ifnum#1>5 \ifnum#2<100000 0\fi
\ifnum#1>6 \ifnum#2<1000000 0\fi
\ifnum#1>7 \ifnum#2<10000000 0\fi
\ifnum#1>8 \ifnum#2<100000000 0\fi
\ifnum#1>9 \ifnum#2<1000000000 0\fi
\fi\fi\fi\fi\fi\fi\fi\fi\fi
\expandafter\@firstofone\expandafter{\number#2}%
}
\makeatother
\padnum
也是可扩展的,这意味着,它可以安全地用作文件名、标签名的一部分……
用法。第一个参数指定位数,必要时应以前导零填充。第二个参数是要格式化的数字。然后\padnum{3}{\lessonnumber}
使用\lessonnumber
as04
将扩展为004
。
答案3
我将使用\num
来自siunitx 包。如手册中所述,的输出\num
是高度可配置的。要删除所有零,您只需输入
\num[minimum-integer-digits=1]{\lessonnumber}
(如果\lessonnumber
是0
或00
等,则会打印0
。)要打印数字的“完整形式”,只需使用\lessonnumber
或\num[\lessonnumber]
。相反,如果您想用\lessonnumber
前导零填充三位数,您可以输入
\num[minimum-integer-digits=3]{\lessonnumber}
更多示例请参见以下输出
来自以下代码:
\documentclass{article}
\usepackage{siunitx}
\begin{document}
\num[minimum-integer-digits=1]{04} \num[minimum-integer-digits=3]{4}
\num[minimum-integer-digits=1]{004} \num[minimum-integer-digits=4]{4}
\num[minimum-integer-digits=1]{00004444} \num{00004}
\end{document}
答案4
只需利用 TeX 在请求时去掉前导零的事实<number>
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\printnumber}{sm}
{
\IfBooleanTF{#1}
{ \int_to_arabic:n { #2 } }
{ #2 }
}
\ExplSyntaxOff
\newcommand{\lessonnumber}{04}
\begin{document}
Full number: \printnumber\lessonnumber
Strip zero: \printnumber*\lessonnumber
\end{document}
实际上,如果没有*
,宏\printnumber
什么也不做;但是我们可以*
根据需要使用来有选择地去除零。
局限性:仅可能达到 2 31 –1 的数字。