3

For a project I am working on I want to automatically 'calculate' the ordinal suffix for numbers. I need to calculate ordinals for various numbers, and later also write them to an external file (the project itself is a fully automated agenda). However, calculating ordinals for different numbers results in errors. I approach this in the following manner:

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

The problem here is that the intended results should be 2nd & 1st. The output is 2st & 1st, however. I think I understand why this happens: \@@meetingNumbersconly and \@@lastMeetingNumbersconly hold the same value, but this is not the intention.

The solution would be as easy as moving the following bit of code within the \@getSuperscript command.

\StrRight{#1}{2}[\@lasttwo]%
\StrRight{#1}{1}[\@lastone]%

However, this is not possible as later in the code, I try to write the superscript to an external file using \write\general{<li>\@@lastMeetingNumbersc</li>}. By trying to do so, other errors arise.

Another solution would be to make two commands for \@getSuperscript, one for each ordinal. Since I want to keep the code as clean as possible, I also rather not do this.

I have been fiddling around with expansion for a few hours but I have not really found a way to achieve my goal: having the intended output 2nd & 1st while also being able to write the intended results to a file. Does anybody have any suggestions besides duplicated code?

Thanks in advance.

10
  • 2
    Please provide a short working example of code that demonstrates the issue, rather than just a non-compilable code snippet. – Steven B. Segletes Feb 18 at 13:57
  • @StevenB.Segletes I have added a MWE, please let me know if you need anything more :) – G. de Man Feb 18 at 14:10
  • 2
    Why don't you \usepackage[super]{nth} then \nth{2} \& \nth{1}? – Phelype Oleinik Feb 18 at 14:17
  • 1
    beware \ifnum\lasttwo>10\ifnum... will force the second \fnum test to be executed before the first, as it will be looking for further digits to follow 10 (you want a space after 10) – David Carlisle Feb 18 at 14:19
  • 1
    also a % here does nothing \else% but you have missing % after { and } in several lines which will cause spurious white space in output. – David Carlisle Feb 18 at 14:21
3

The problem with your commands is that after doing \meetingNumberDefault{1}, you will have \lasttwo be 2 and \lastone be 2, and \meetingNumbersconly will be \getSuperscript{2}, and not st (use \show\meetingNumbersconly to see). Then, you do \meetingNumberLast{1} which changes \lasttwo and \lastone again to 1. Then when you use \meetingNumbersconly it will get the suffix for the last value of \lasttwo and \lastone, thus you get st in both cases (just try changing the order of \meetingNumberDefault{2} and \meetingNumberLast{1} in the preamble).

That happens because \renewcommand does not evaluate the definition, it just stores it. To force \getSuperscript to expand to st or nd or whatever, you need \edef instead of \renewcommand (the e in \edef stands for expanded). If you change that, \meetingNumbersconly and \lastMeetingNumbersconly will be nd and st.

But instead, I suggest you just use the nth package (with the option super for superscripts):

\documentclass{article}
\usepackage[super]{nth}
\begin{document}
  \nth{2} \& \nth{1}
\end{document}

or, if you need to set the number prior, then maybe something like this:

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

Both examples produce:

enter image description here

1

Here's an implementation with expl3. If \addordinal is used in a \write operation it will output the number in decimal form and the suffix as an argument to \ORDINAL, that you can define as you wish (possibly not as a superscript, please).

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

The idea is to check for the special cases 11, 12 and 13 first; in the other cases, the suffix is appended based on the last digit, computed with modulo 10 operation.

In the example, the final \edef emulates what happens in a \write operation.

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.