Rand Stats



Raku Lingua::NumericWordForms

🇦🇿 🇧🇬 🇨🇿 🇬🇧 🇫🇷 🇬🇷 🇯🇵 🇮🇷 🇵🇱 🇵🇹 🇷🇺 🇪🇸 🇺🇦


This repository provides a Raku package with functions for the generation, parsing, and interpretation of numeric word forms in different languages.

The initial versions of the code in this repository can be found in the GitHub repository [AAr1].

The Raku package Lingua::Number, [BL1], provides word forms (cardinal, ordinal, etc.) generation in many languages. (But at least for one language the produced forms are incorrect.)

The Raku package Lingua::EN::Numbers, [SS1], also provides word forms (cardinal, ordinal, etc.) generation in English.

The parsers and interpreters of this package can be seen as complementary to the functions in [BL1, SS1].

Remark: Maybe a more complete version of this package should be merged with Lingua::Number, [BL1].

Remark: I can judge the quality of the results only of the languages: Bulgarian, English, and Russian. The numeric word form interpreters for the rest of the languages pass testing, but they might have potentially many deficiencies. (That are easily detected by people who have mastered those languages.)

Remark: The package also "understands" (i.e. parses and translates to) Koremutake.


Package installations from both sources use zef installer (which should be bundled with the "standard" Rakudo installation file.)

To install the package via Zef's ecosystem use the shell command:

zef install Lingua::NumericWordForms

To install the package from the GitHub repository use the shell command:

zef install https://github.com/antononcube/Raku-Lingua-NumericWordForms.git



The generation of numeric word forms is a secondary goal of this package. Currently only generation of English numeric word forms is implemented. (I plan to implement Bulgarian word forms generation soon...) Here are examples:

use Lingua::NumericWordForms;
say to-numeric-word-form(8093);
say to-numeric-word-form(8093, 'Bulgarian'); # not implemented yet
say to-numeric-word-form(8093, 'Russian');   # not implemented yet
#ERROR: Using English, not Bulgarian.
#ERROR: Using English, not Russian.
# eight thousand, ninety three
# eight thousand, ninety three
# eight thousand, ninety three

The first argument of to-numeric-word-form can be:

Here are examples of the latter two:

to-numeric-word-form('123; 232; 898_934').join('; ');
# one hundred twenty three; two hundred thirty two; eight hundred ninety eight thousand, nine hundred thirty four
to-numeric-word-form([321, '992', 100_904]).join('; ');
# three hundred twenty one; nine hundred ninety two; one hundred thousand, nine hundred four


Interpretation of numeric word forms is the primary goal of this package. Multiple language are supported. Here are examples:

use Lingua::NumericWordForms;
say from-numeric-word-form('one thousand and twenty three');
say from-numeric-word-form('хиляда двадесет и три', 'Bulgarian');
say from-numeric-word-form('tysiąc dwadzieścia trzy', 'Polish');
say from-numeric-word-form('одна тысяча двадцать три', 'Russian');
say from-numeric-word-form('mil veintitrés', 'Spanish');
# 1023
# 1023
# 1023
# 1023
# 1023

The function from-numeric-word-form can take as a first argument:

Here are corresponding examples:

from-numeric-word-form('twenty six');
# 26
from-numeric-word-form(['mil veintitrés', 'dos mil setenta y dos']);
# (1023 2072)
from-numeric-word-form('two hundred and five; триста четиридесет и две; 二十万六十五'):p;
# (english => 205 bulgarian => 342 japanese => 200065)

For more examples see the file NumericWordForms-examples.raku.

Here we retrieve a list of all supported languages:

# (azerbaijani azərbaycan bulgarian czech english español français french greek japanese korean koremutake persian polish polski portuguese português russian spanish ukrainian český ελληνικά български руский український 日本語 한국어)

Remark: In the list above some languages appear twice, with both their English and native names.

Type of the result

The returned result can be an Int object or a Str object -- that is controlled with the adverb number (which by default is True.) Here is an example:

my $res = from-numeric-word-form('one thousand and twenty three'); 
say $res, ' ', $res.WHAT;
# 1023 (Int)
$res = from-numeric-word-form('one thousand and twenty three', :!number); 
say $res, ' ', $res.WHAT;
# 1023 (Str)

Automatic language detection

Automatic language detection is invoked if the second argument is 'Automatic' or not specified:

say from-numeric-word-form('tysiąc dwadzieścia trzy', 'Automatic'):p;
# polish => 1023
say from-numeric-word-form(['tysiąc dwadzieścia trzy', 'twenty three']):p;
# (polish => 1023 english => 23)

The adverb :p specifies whether the result should be a Pair object or a List of Pair objects with the detected languages as keys.


Translation from one language to another:

translate-numeric-word-form('хиляда двадесет и три', 'Bulgarian' => 'English');
# one thousand, twenty three

Remark: Currently that function translates to English and Koremutake only.

Here is are Russian to Koremutake example:

my $numForm = "три тысячи восемьсот девяносто";
my $trRes = translate-numeric-word-form($numForm, 'automatic' => 'Koremutake');
say "Given           : $numForm";
say "To Koremutake   : $trRes";
say "From Koremutake : {from-numeric-word-form($trRes)}";
# Given           : три тысячи восемьсот девяносто
# To Koremutake   : jami
# From Koremutake : 3890


This package provides (exports) roles that can be used in grammars or roles in other packages, applications, etc.

For example, see the roles:


A grammar or role that does the roles above should use the rule:


For code examples see the file Parsing-examples.raku.

Remark: The role Lingua::NumericWordForms::Roles::WordedNumberSpec and the corresponding actions class Lingua::NumericWordForms::Actions::WordedNumberSpec are "abstract". They were introduced in order to have simpler roles and actions code (and non-duplicated implementations.) Hence, that role and class should not be used in grammars and roles outside of this package.


The following TODO items are ordered by priority, the most important are on top.

  1. Expand parsing beyond trillions

  2. Automatic determination of the language

  3. Word form generation:

    • English
    • Bulgarian
    • Russian
    • General algorithm
  4. Documentation of the general programming approach.

    • What are the main challenges?
    • How the chosen software architecture decisions address them?
    • Concrete implementations walk-through.
    • How to implement / include a new language?
    • How the random numbers test files were made?
    • Profiling, limitations, alternatives.
  5. Full, consistent Persian numbers parsing.

    • Currently, Persian number parsing works only for numbers less than 101.
  6. General strategy for parsing and interpretation of numeric word forms of East Asia languages

    • Those languages use groupings based on 10^4 instead of 10^3.
    • Implementation for Japanese.
  7. Implement parsing of ordinal numeric word forms

    • English, French, Greek, and Spanish

    • Bulgarian

    • Czech, Russian, Ukrainian, Polish

    • Japanese

    • Koremutake

    • Portuguese

    • Azerbaijani

    • Korean

      • Implemented to a point.
    • Persian

      • Implemented to a point.
    • Sanskrit

  8. Implement parsing of year "shortcut" word forms, like "twenty o three"

  9. Implement parsing of numeric word forms for rationals, like "five twelfths"

  10. Translation function (from one language to another)

Collaboration notes

feat:Implemented the parsing of Danish numeric word forms.
docs:Added documentation of right-to-left word forms parsing.
fix(Persian):Corrected tests for numbers larger that 1000.
test:Added new corner cases tests.
test(Ukrainian):Added new tests.



[AAr1] Anton Antonov, Raku::DSL::Shared.

[BL1] Brent "Labster" Laabs, Lingua::Number.

[SS1] Larry Wall, Steve Schulze, Lingua::EN::Numbers.

Anton Antonov
Florida, USA
April-May, 2021