13

In the documentclass I am writing, the user will input an integer such as \lessonnumber as an integer with possibly a number of leading zeroes, e.g. 4 as 04. At some places in the document I will need the full form (04) and at others I only want to common form (4). How can I accomplish this?

  • How will the value of \lessonnumber be captured? Will it be entered as a string, e.g., via \newcommand\lessonnumber{"04"}? Please advise. – Mico Jun 17 '15 at 16:39
  • @Mico: As \renewcommand{\lessonnumber}{04}. – Simon Kuang Jun 17 '15 at 16:44
15

I introduce \stripzero, which will work with the argument either in or not in braces. The argument can be an expandable macro.

The macro works recursively. The definition of \stripzero first expands its argument, which is needed to allow operation on macros such as \lessonnumber. Once the argument is expanded, it calls on the recursion routine, which compares the next token to a 0. If it is not a zero, it prints the token and stops. If the token is a 0, it ignores/discards it, and calls itself again to look at the next token.

The trick to avoid the macro looking at the \else as its next argument is to \expandafter the macro, so as to absorb the \else. If I have the recursion call upon \stripzero (rather than \stripzerohelp), the \expandafter is not necessary. However, a two-macro recursion is also not most efficient, so I left the recursion routine calling directly upon itself, while retaining the \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}

enter image description here

Marc raises the interesting question of how to handle an argument of pure zeroes. The above MWE strips them all away. However, that may not be desired. It may be desired to print out a single 0 if the argument is a string of zeros.

Therefore, I provide the following alternate implementation that checks the first non-zero token. If it is a digit, it behaves as before. But if the following token is not a digit, it concludes the number was a string of pure zeros and outputs a single 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}

enter image description here

  • I can see that \stripzero recursively parses the integer beginning with the first digit. Can you briefly explain how it does this? – Simon Kuang Jun 17 '15 at 16:43
  • @SimonKuang I have added some explanation. – Steven B. Segletes Jun 17 '15 at 16:48
  • Thank you! (I am learning TeX.) I still do not understand \stripzerohelp completely. How does \stripzero\else discard the first token? – Simon Kuang Jun 17 '15 at 16:53
  • @SimonKuang The very first token comes into \stripzerohelp as #1. If it is a 0 token, nothing is done with it and the recursion is called again. It is effectively discarded. In my re-revision, I employ a \expandafter prior to \stripzerohelp to absorb the \else. – Steven B. Segletes Jun 17 '15 at 16:59
  • The macro \stripzero will fail if its argument is a sequence of zeros. (Then again such areguments may never occur.) – user10274 Jun 17 '15 at 17:54
13

Numbers smaller than 231-1

If the number fits in TeX's number range, then the number can be normalized with vanilla TeX's \number:

\number\lessonnumber\relax

The \relax at the end (or an empty curly brace pair) prevents that TeX looks for more digits after \lessonnumber. An expandable version must use a different trick:

\makeatletter
\newcommand*{\normalizedlessonnumber}{%
  \expandafter\@firstofone\expandafter{\number\lessonnumber}%
}
\makeatother

Then the closing curly brace serves as stopper for the TeX's digit scanner and the the curly braces will be gone as argument braces of \@firstofone.

The expandable e-TeX version with additional support for some arithmetic operations is:

\the\numexpr(\lessonnumber)\relax

Unlimited integers

An expandable normalization for unlimited integer numbers an be done by \bigintcalcNum of package bigintcalc:

\bigintcalcNum{\lessonnumber}

Adding leading zeros

If the number fits in TeX's integer range, then the following macro \padnum adds leading zeros (taken from my answer to this question).

\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 is also expandable, that means, it can be safely used as part of file names, label names, ...

Usage. The first argument specifies the number of digits, which should be filled with leading zeros, when necessary. The second argument is the number to be formatted. Then \padnum{3}{\lessonnumber} with \lessonnumber as 04 will expand to 004.

  • 6
    Hopefully the number of lessons won't be higher than 2^{31}-1 :-) – Gonzalo Medina Jun 17 '15 at 17:44
  • (I think) You are missing an \expandafter before the brace in \normalizedlessonnumber definition. – Manuel Jun 17 '15 at 18:55
8

I would use the \num command from the siunitx package. As explained in the manual the output of \num is highly configurable. To remove all of the zeros you could just type

\num[minimum-integer-digits=1]{\lessonnumber}

(If \lessonnumber is 0 or 00 etc this will print 0.) To print the "full form" of the number just use \lessonnumber or \num[\lessonnumber]. Conversely, if you wanted to pad \lessonnumber to a three digit number with leading zeros you can type

\num[minimum-integer-digits=3]{\lessonnumber}

For some more examples, you get the following output

enter image description here

from the following code:

\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}
  • +1 for use of the \num macro. Unfortunately, your method won't automatically show the correct number of leading zeros if, say, the lesson number is "55" and the student has entered "055". Put differently, the method isn't fully automatic since the optional argument of \num needs to know the number of significant digits (without any leading zeros) in "lesson number". – Mico Jun 17 '15 at 16:34
  • @Mico Perhaps I misunderstand, but this seems to be OK. I have changed the MWE to use 054 and it produces what I expect. What am I missing? – Andrew Jun 17 '15 at 16:46
  • Sorry for not being clear: I'm assuming it's not known in advance (a) how many significant digits \lessonnumber will contain and (b) how many leading zeros there may be. With your method, the correct value of the option minimum-integer-digits will depend on both of these unknowns. – Mico Jun 17 '15 at 17:05
  • @Mico My MWE shows that this is not a problem. You just print \lessonnumber if you want to print the input value and otherwise you use \num[minimum-integer-digits=1]{\lessonumber}. The latter will strip all leading zeros unless \lessonnumber is zero, in which case it prints 0. – Andrew Jun 17 '15 at 17:10
  • Thanks. I realize now I was confused. You may want to simplify your MWE to highlight the direct use of \lessonnumber for the full form vs. \num[minimum-integer-digits=1]{\lessonumber} for the stripped form. – Mico Jun 17 '15 at 17:16
7

Here's a LuaLaTeX-based solution.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}

% Define "\strippednumber"
\newcommand\strippednumber[1]{\directlua{tex.sprint(#1)}}

\begin{document}

\newcommand\lessonnumber{0004}  % we assume that the students won't enter arbitrary junk...

The value of \verb+\lessonnumber+, as entered by the student, is \lessonnumber.

The value of \verb+\lessonnumber+ without the leading zeros is \strippednumber{\lessonnumber}.
\end{document}

Aside: Under the method proposed here, numbers with more than fourteen [14!] significant digits will be rendered automatically in "scientific" notation. I trust this condition isn't particularly restrictive for the use case you've laid out. :-)

6

Just use the fact that TeX strips off leading zeros when requested for a <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}

Actually, without *, the macro \printnumber does nothing; but we can use the * to selectively strip off the zero when we wish to.

enter image description here

Limitation: only numbers up to 231–1 are possible.

1

This can be simply achieved with \number.

\documentclass{article}

\begin{document}

\makeatletter
\def\lessonnumber{\@ifstar{\@lessonnumber}{\@lessonnumber@stripzero}}
\def\@lessonnumber#1{#1}
\def\@lessonnumber@stripzero#1{\number#1}
\makeatother

\lessonnumber{4}

\lessonnumber{04}

\lessonnumber*{004} 

\end{document}

The output will be:

enter image description here

0

A simple but flexible solution is a counter and the fmtcount package:

MWE

\documentclass{article}
\usepackage{fmtcount}
\padzeroes[2]\newcounter{lesson}
\def\Lesson{{\addtocounter{lesson}{1}\padzeroes[2]%
\vskip1em\large\bfseries Lesson~\decimal{lesson}}\par\vskip.5em}
\begin{document}
\Lesson Some text of the lesson \arabic{lesson} 
\Lesson Some text of the lesson \padzeroes[7]\decimal{lesson}  \decimalnum{24}
\Lesson Some text of the lesson \padzeroes[3]\decimal{lesson}, not the \decimalnum{4}
\Lesson Some text of the lesson \padzeroes[1]\decimal{lesson}\par 
$\vdots$\addtocounter{lesson}{4}
\Lesson Some text of the lesson \decimal{lesson}
\Lesson Some text of the lesson \decimal{lesson}
\Lesson Some text of the lesson \ordinalstring{lesson} 
\Lesson Some text of the lesson \ordinal{lesson} 
\Lesson Some text of the lesson \Roman{lesson} 
\end{document}

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.