对于我正在开展的一个项目,我想自动“计算”数字的序数后缀。我需要计算各种数字的序数,然后将它们写入外部文件(项目本身是一个完全自动化的议程)。但是,计算不同数字的序数会导致错误。我采用以下方式解决此问题:
\documentclass{article}
\usepackage{xstring}
\newcommand\meetingNumbersconly{}
\newcommand\lastMeetingNumbersconly{}
%% Determine superscript of given raw number
\newcommand\getSuperscript[1]{%
\ifnum\lasttwo>10\ifnum\lasttwo<14 th\fi\else
\ifnum\lastone>3 th\else%
\ifnum\lastone=0 th\else%
\ifnum\lastone=3 rd\else%
\ifnum\lastone=2 nd\else st%
\fi\fi\fi\fi%
\fi%
}
\newcommand\meetingNumberDefault[1]{
\StrRight{#1}{2}[\lasttwo]%
\StrRight{#1}{1}[\lastone]%
\renewcommand\meetingNumbersconly{\getSuperscript{#1}}
}
\newcommand\meetingNumberLast[1]{
\StrRight{#1}{2}[\lasttwo]%
\StrRight{#1}{1}[\lastone]%
\renewcommand\lastMeetingNumbersconly{\getSuperscript{#1}}
}
\meetingNumberDefault{2}
\meetingNumberLast{1}
% \newwrite\general
% \openout\general=information.txt
% \write\general{\lastMeetingNumbersc}
% \closeout\general
\begin{document}
2\textsuperscript{\meetingNumbersconly} \& 1\textsuperscript{\lastMeetingNumbersconly}
\end{document}
这里的问题是,预期结果应该是2nd & 1st
。但是输出是2st & 1st
。我想我明白为什么会发生这种情况:\@@meetingNumbersconly
和\@@lastMeetingNumbersconly
保持相同的值,但这不是意图。
解决方案很简单,只需在命令中移动以下代码即可\@getSuperscript
。
\StrRight{#1}{2}[\@lasttwo]%
\StrRight{#1}{1}[\@lastone]%
但是,这是不可能的,因为在代码的后面,我尝试使用 将上标写入外部文件\write\general{<li>\@@lastMeetingNumbersc</li>}
。尝试这样做时,会出现其他错误。
另一个解决方案是为 制作两个命令\@getSuperscript
,每个序数一个。因为我想让代码尽可能干净,所以我宁愿不这样做。
我已经花了几个小时来研究扩展,但我还没有找到实现目标的方法:获得预期的输出2nd & 1st
,同时还能将预期的结果写入文件。除了重复的代码之外,还有人有什么建议吗?
提前致谢。
答案1
你的命令的问题在于,执行完之后\meetingNumberDefault{1}
,你将拥有\lasttwo
、2
拥有\lastone
、2
将会\meetingNumbersconly
拥有\getSuperscript{2}
、拥有不是 st
(使用\show\meetingNumbersconly
来查看)。然后,您再次执行将和\meetingNumberLast{1}
更改为 的操作。然后当您使用它时,将获得和的最后一个值的后缀,因此您会在两种情况下都得到(只需尝试更改序言中和的顺序)。\lasttwo
\lastone
1
\meetingNumbersconly
\lasttwo
\lastone
st
\meetingNumberDefault{2}
\meetingNumberLast{1}
发生这种情况是因为\renewcommand
没有评估定义,它只是商店它。要强制\getSuperscript
扩展为st
或nd
或任何其他,您需要\edef
而不是\renewcommand
(e
中的\edef
代表扩展)。如果您更改它,\meetingNumbersconly
和\lastMeetingNumbersconly
将是nd
和st
。
但是,我建议您只使用该nth
包(带有super
上标选项):
\documentclass{article}
\usepackage[super]{nth}
\begin{document}
\nth{2} \& \nth{1}
\end{document}
或者,如果您需要预先设置数字,那么可能是这样的:
\documentclass{article}
\usepackage[super]{nth}
\newcommand\meetingNumberDefault[1]{%
\getmeetingnumber\meetingNumbersconly{#1}}
\newcommand\meetingNumberLast[1]{%
\getmeetingnumber\lastMeetingNumbersconly{#1}}
\newcommand\getmeetingnumber[2]{%
\begingroup
\let\nthscript\relax
\xdef#1{\nth{#2}}%
\endgroup}
\meetingNumberDefault{2}
\meetingNumberLast{1}
\begin{document}
\meetingNumbersconly\ \& \lastMeetingNumbersconly
\end{document}
两个示例都产生:
答案2
以下是 的实现expl3
。如果\addordinal
在操作中使用 ,\write
它将以十进制形式输出数字,并将后缀作为 的参数输出\ORDINAL
,您可以根据需要定义后缀(请不要将其定义为上标)。
\documentclass{article}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\addordinal}{m}
{% #1 should be something that TeX interprets as an integer
\int_to_arabic:n { #1 }
\exp_args:Ne \ORDINAL { \deman_compute_suffix:n { #1 } }
}
\NewDocumentCommand{\ORDINAL}{m}{\textsuperscript{#1}}% how ugly is it?
\cs_new:Nn \deman_compute_suffix:n
{
\int_case:nnF { #1 }
{% special cases
{11}{th}
{12}{th}
{13}{th}
}
{ \__deman_compute_suffix_normal:n { #1 } }
}
\cs_new:Nn \__deman_compute_suffix_normal:n
{
\int_case:nnF { \int_mod:nn { #1 } { 10 } }
{
{1}{st}
{2}{nd}
{3}{rd}
}
{th}
}
\ExplSyntaxOff
\begin{document}
\addordinal{1}
\addordinal{2}
\addordinal{3}
\addordinal{4}
\addordinal{10}
\addordinal{11}
\addordinal{12}
\addordinal{13}
\addordinal{19}
\addordinal{20}
\addordinal{21}
\addordinal{100}
\addordinal{101}
A ``random'' number \addordinal{\time}
Emulate a write: \edef\writtenout{\addordinal{121}}
\texttt{\meaning\writtenout}
\end{document}
其思路是首先检查特殊情况 11、12 和 13;在其他情况下,根据最后一位数字附加后缀,并通过模 10 运算计算。
在示例中,最后\edef
模拟了操作中发生的情况\write
。