1

I need to define counters using fractur fonts and hebrew alphabet. For the greek alphabet I'm using the package engrec. Any suggestion? Thanks

2
  • 1
    You can use the \ifcase construction (which is how \alph does it). Commented Feb 24, 2020 at 13:48
  • @JohnKormylo, thanks for the prompt reply, but, being a sort of newbie, could you elaborate a little further?
    – Guidone
    Commented Feb 24, 2020 at 14:57

2 Answers 2

6

What John Kormylo probably meant is that, if it is reasonable to enumerate all cases that can possibly occur, you can paraphrase the definition of \alph in LaTeX, which relies on TeX's \ifcase conditional as follows:

\def\alph#1{\expandafter\@alph\csname c@#1\endcsname}

\def\@alph#1{%
  \ifcase#1\or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or
   k\or l\or m\or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or
    y\or z\else\@ctrerr\fi}

For instance, the following is a dumb way to format a LaTeX counter using the famous (?) Shadok numeral system. This is a base-4 positional numeral system where the available symbols for each digit are Ga = 0, Bu = 1, Zo = 2 and Meu = 3.

\documentclass{article}
\usepackage{pgffor}     % only for the demo code
\usepackage{multicol}   % only for the demo code

\makeatletter
\newcommand*{\@shadokNumber}[1]{%
  \ifcase #1% #1 is supposed to be a <number>
        Ga\or      Bu\or      Zo\or      Meu\or
      BuGa\or    BuBu\or    BuZo\or    BuMeu\or
      ZoGa\or    ZoBu\or    ZoZo\or    ZoMeu\or
     MeuGa\or   MeuBu\or   MeuZo\or   MeuMeu\or
    BuGaGa\or  BuGaBu\or  BuGaZo\or  BuGaMeu\or
    BuBuGa\or  BuBuBu\or  BuBuZo\or  BuBuMeu\or
    BuZoGa\or  BuZoBu\or  BuZoZo\or  BuZoMeu\or
   BuMeuGa\or BuMeuBu\or BuMeuZo\or BuMeuMeu\or
    ZoGaGa\or  ZoGaBu\or  ZoGaZo\or  ZoGaMeu\or
    ZoBuGa\or  ZoBuBu\or  ZoBuZo\or  ZoBuMeu\or
    ZoZoGa\or  ZoZoBu\or  ZoZoZo\or  ZoZoMeu\or
   ZoMeuGa\or ZoMeuBu\or ZoMeuZo\or ZoMeuMeu\or
   MeuGaGa\or  MeuGaBu\or  MeuGaZo\or  MeuGaMeu\or
   MeuBuGa\or  MeuBuBu\or  MeuBuZo\or  MeuBuMeu\or
   MeuZoGa\or  MeuZoBu\or  MeuZoZo\or  MeuZoMeu\or
  MeuMeuGa\or MeuMeuBu\or MeuMeuZo\or MeuMeuMeu\or BuGaGaGa% = 64 in decimal
  % etc.
  \else \@ctrerr \fi
}

\newcommand*{\shadokNumber}[1]{%
  \expandafter\@shadokNumber\csname c@#1\endcsname
}
\makeatother

\newcounter{myctr}

\begin{document}

\begin{multicols}{3}
  \noindent
  \foreach \i in {0,...,64} {%
    \shadokNumber{myctr}\\
    \stepcounter{myctr}%
  }%
  etc.
\end{multicols}

\end{document}

enter image description here

Generalization (positional numeral systems)

Regular positional numeral systems can be handled with generic code. What follows borrows from the expl3 implementation of \int_to_base:nn and adapts it in order to provide formatting of arbitrary integers in the Shadok numeral system. The available symbols for digits here are still Ga, Bu, Zo and Meu (several tokens each), but you can replace them with any LaTeX code of your choice. Just don't forget to update the number of available symbols in \g_guidone_nb_symbols_int (here: 4).

\documentclass{article}
\usepackage{expl3}
\usepackage{multicol}   % only for the demo code

\ExplSyntaxOn
% Ga, Bu, Zo, Meu: 4 symbols. Replace with the number of digit symbols you have.
\int_const:Nn \c_guidone_nb_shadok_digit_symbols_int { 4 }

% Replace Ga, Bu, Zo, Meu with LaTeX code producing each possible digit symbol.
\cs_new:Npn \__guidone_to_shadok_digit:n #1
  {
    \exp_after:wN \__guidone_remove_fi:nw
    \if_case:w #1 \c_space_token  % this finishes the <number>
      { Ga }
    \or:
      { Bu }
    \or:
      { Zo }
    \or:
      { Meu }
    \else:
      { \msg_expandable_error:nnn { guidone } { too-large-for-a-digit } {#1} }
    \fi:
  }

\msg_new:nnn { guidone } { too-large-for-a-digit }
  { Too~large~for~a~digit:~\exp_not:n {#1}. }

% Define aliases that can be used outside \ExplSyntaxOn ... \ExplSyntaxOff.
\cs_new_eq:NN \nbShadokDigitSymbols \c_guidone_nb_shadok_digit_symbols_int
\cs_new_eq:NN \toShadokDigit \__guidone_to_shadok_digit:n

% The \exp_stop_f: stops f-expansion from the \__guidone_deliver:nfw call.
% \__guidone_to_digit:n should normally be used within f-expansion,
% otherwise the \exp_stop_f: (implicit space token) will precede the wanted
% result (digit).
\cs_new:Npn \__guidone_remove_fi:nw #1#2\fi:
  { \fi: \exp_stop_f: #1 }

% #1: base (= number of available digit symbols)
% #2: function such as \__guidone_to_shadok_digit:n (input: a number between 0
%     and #1 - 1, both inclusive; output: a single digit)
% #3: number to format
\cs_new:Npn \guidone_format_number:nNn #1#2#3
  {
    \exp:w
    \__guidone_to_base:nnN {#3} {#1} #2
    \q_stop
  }

% The \*_to_base:* functions are based on code from l3int.dtx, with
% modifications so that \guidone_format_number:nNn can deliver potentially
% sensitive material with \exp_not:n in exactly two expansion steps.
\cs_new:Npn \__guidone_to_base:nnN #1
  { \exp_args:Nf \__guidone_to_base_aux:nnN { \int_eval:n {#1} } }

\cs_new:Npn \__guidone_to_base_aux:nnN #1#2#3
  {
    \int_compare:nNnTF {#1} < { 0 }
      { \exp_args:No \__guidone_to_base:nnnN { \use_none:n #1 } {#2} { - } #3 }
      { \__guidone_to_base:nnnN {#1} {#2} { } #3 }
  }

% #1: empty or minus sign
% #2: leftmost digit of the number (i.e., the last digit produced by
%     \guidone_format_number:nNn)
% #3: the remaining digits
%
% The \exp_end: terminates the expansion started by \exp:w in
% \guidone_format_number:nNn.
\cs_new:Npn \__guidone_deliver:nnw #1#2#3\q_stop
  { \exp_end: \exp_not:n { #1#2#3 } }

\cs_generate_variant:Nn \__guidone_deliver:nnw { nf }

\cs_new:Npn \__guidone_to_base:nnnN #1#2#3#4
  {
    \int_compare:nNnTF {#1} < {#2}
      { \__guidone_deliver:nfw {#3} { #4 {#1} } }
      {
        \exp_args:Nf \__guidone_to_base:nnnnN
          { #4 { \int_mod:nn {#1} {#2} } }
          {#1}
          {#2}
          {#3}
          #4
      }
  }

\cs_new:Npn \__guidone_to_base:nnnnN #1#2#3#4#5
  {
    \exp_args:Nf \__guidone_to_base:nnnN
      { \int_div_truncate:nn {#2} {#3} }
      {#3}
      {#4}
      #5
    #1
  }

% Define aliases that can be used outside \ExplSyntaxOn ... \ExplSyntaxOff.
% Note that \guideoneFormatNumber is fully expandable and delivers the result
% in two expansion steps.
\cs_new_eq:NN \guideoneFormatNumber \guidone_format_number:nNn
\cs_new_eq:NN \intstepinline \int_step_inline:nnnn
\ExplSyntaxOff

% What follows \shadokNumber in the input stream will be the third argument of
% \guideoneFormatNumber, i.e.: the number to convert.
\newcommand*{\shadokNumber}{%
  \guideoneFormatNumber{\nbShadokDigitSymbols}{\toShadokDigit}%
}

\newcounter{myctr}

% Make it so that \themyctr uses our custom numeration style.
\renewcommand{\themyctr}{%
  \shadokNumber{\value{myctr}}%
}


\begin{document}

\begin{multicols}{3}
  \noindent
  % Initial value, step, final value
  \intstepinline{0}{1}{64}{%
    \themyctr\\
    \stepcounter{myctr}%
  }%
  etc.
\end{multicols}

Most importantly:
\[ 65536 = \shadokNumber{65536} \]
and  % We can handle any 〈integer expression〉, including negative ones.
\[ -(3\times 64 + 2\times 16 + 1\times 4 + 0\times 1) =
   \shadokNumber{-1*(3*64 + 2*16 + 1*4 + 0*1)} \]

% Verify that the desired result is obtained in exactly two expansion steps.
% If you uncomment the following seven lines, TeX will print on the terminal:
%   > \exp_not:n {-MeuZoBuGa}.
%
% \def\zzz#1{\expandafter\showtokens\expandafter{#1}}
% \expandafter\zzz\expandafter{%
%   \guideoneFormatNumber
%     {\nbShadokDigitSymbols}
%     {\toShadokDigit}
%     {-1*(3*64 + 2*16 + 1*4 + 0*1)}%
% }

\end{document}

enter image description here

As you can see from the following definition:

\newcommand*{\shadokNumber}{%
  \guideoneFormatNumber{\nbShadokDigitSymbols}{\toShadokDigit}%
}

the only thing you need to do in order to define conversion functions for other numeral systems in the same document is to pass \guideoneFormatNumber:

  • the number of available digit symbols, i.e. the base (\nbShadokDigitSymbols is 4 in our example);

  • a function such as \toShadokDigit (i.e., \__guidone_to_shadok_digit:n) that converts a number between 0 and base - 1 to its 1-digit representation in the destination numeral system.

The number to convert has to come next in the input stream and doesn't need to be grabbed as an argument by \shadokNumber (this is a small optimization).

Hebrew numeration

Hebrew numeration seems to be less regular than what the above code is designed to handle. If only a small number of values are needed, you can use the first approach. Otherwise, I'm afraid you'll need another conversion algorithm. The polyglossia package provides commands such as \hebrewnumeral, \Hebrewnumeral and \Hebrewnumeralfinal that might be of interest to you. You might be interested in this question for instance. Alas, I don't know Hebrew, so can't help you more in this area.

2
  • thank you very much for your exhaustive answer. Just what I needed.
    – Guidone
    Commented Feb 28, 2020 at 9:53
  • You're welcome. :-) You may want to check the updated answer: I made the interface a bit more flexible in the second piece of code.
    – frougon
    Commented Feb 28, 2020 at 15:56
3

With babel 3.41, just released, comes a bunch of predefined additive and alphabetic numerals for some languages, based on the CSS ready-made counter styles (numeric styles have been available since babel 3.20). More importantly, they are defined with the help of a set of key/value pairs in ini files, which means you can define your own styles with \babelprovide, too. Note this tool is meant for xetex and luatex, but it may work in pdftex. Here is an example with some explanations.

\documentclass{article}

\usepackage[italian]{babel}

\babelprovide[
     % To define a purely alphabetic numeral, just provide a space-
     % separated list of ordered symbols, characters, etc. Let's name
     % it 'lower' (you can choose another name):
  counters/lower=Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll,
     % For additive numerals, a set of four keys are required, numbered
     % with a digit from 1 (for 1-9) to 4 (for 1000-9000) preceded by a
     % dot. Let's name it 'letters':
  counters/letters.1= a b c d e f g h i,
  counters/letters.2= k l m n o p q r s, 
  counters/letters.3= A B C D E F G H I,
  counters/letters.4= K L M N O P Q R S,
     % Fixed representations for specific values of additive numerals
     % are allowed, too. Just end the key with dot, uppercase F, dot,
     % number:
  counters/letters.F.55 = Oohh
     % Redefining \alph to print these numerals is simple:
  alph = letters    
  ]{italian}

\begin{document}

\localenumeral{lower}{4}     % Prints Dd

\localenumeral{lower}{2}     % Prints Bb

\localenumeral{letters}{956} % Prints Iof

\localenumeral{letters}{55}  % Prints Oohh

\alph{page}  % Prints a, because it's the first page and \alph uses the
             % 'letters' numerals

\end{document}

For further details, see What's new in babel 3.41.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .