On this page
Converting numbers to words#
NumberToWords::convert() spells an integer out as words. Persian (fa) is the default and covers every integer below 1021.
<?php
require 'vendor/autoload.php';
use RtlyKit\Number\NumberToWords;
use function RtlyKit\number_to_words;
echo NumberToWords::convert(0), "\n"; // صفر
echo NumberToWords::convert(21), "\n"; // بیست و یک
echo NumberToWords::convert(115), "\n"; // صد و پانزده
echo NumberToWords::convert(1001), "\n"; // یک هزار و یک
echo NumberToWords::convert(12345), "\n"; // دوازده هزار و سیصد و چهل و پنج
echo NumberToWords::convert(-45), "\n"; // منفی چهل و پنج
echo number_to_words(2000000000), "\n"; // دو میلیارد
echo NumberToWords::convert(1234567), "\n";
// یک میلیون و دویست و سی و چهار هزار و پانصد و شصت و هفت
Words are joined with « و » (and) between all parts. Each scale word follows its group: «هزار» (103), «میلیون» (106), «میلیارد» (109), «تریلیون» (1012), «کوادریلیون» (1015) and «کوینتیلیون» (1018). A group equal to 1 keeps its «یک», so 1000 is «یک هزار». To read a bare «هزار», use fromWords() below. Zero groups are skipped.
Accepted input#
The parameter is typed int|float|string:
- int: the whole PHP range works, including
PHP_INT_MAX: «نه کوینتیلیون و دویست و بیست و سه کوادریلیون ...». - float: must be finite and whole.
3.0gives «سه».1.5throws and is not silently cut. - string: an optional sign and digits in any digit set. Commas,
٬and spaces are removed, so a number copied from a form works. Strings can be longer than a PHP int, up to 21 digits after leading zeros are dropped.
echo NumberToWords::convert('۱۲۳٬۴۵۶'), "\n"; // صد و بیست و سه هزار و چهارصد و پنجاه و شش
echo NumberToWords::convert('1,000,000'), "\n"; // یک میلیون
echo NumberToWords::convert('+7'), "\n"; // هفت
echo NumberToWords::convert('-0'), "\n"; // صفر
echo NumberToWords::convert('999999999999999999999'), "\n";
// نهصد و نود و نه کوینتیلیون و نهصد و نود و نه کوادریلیون ... و نهصد و نود و نه
Errors#
Invalid input throws InvalidNumberException, a subclass of RtlyKitException. Read the stable code with getErrorCode():
| Input | Error code |
|---|---|
1.5, '12a', '' | invalid_number |
NAN, INF | non_finite_number |
| A string longer than 4096 bytes | input_too_long |
1e21, '1000000000000000000000' (22 digits) | number_too_large |
try {
NumberToWords::convert('1000000000000000000000');
} catch (\RtlyKit\Exceptions\InvalidNumberException $e) {
echo $e->getMessage(), ' [', $e->getErrorCode()->value, "]\n";
// Number is too large (limit is 10^21 - 1). [number_too_large]
}
See Error handling to catch every library exception with one type.
Arabic#
Pass 'ar' as the second argument for Modern Standard Arabic. The locale is matched on its first two letters, ignoring case. So 'ar_SA' and 'AR' work, and 'fa_IR' works for Persian.
echo NumberToWords::convert(11, 'ar'), "\n"; // أحد عشر
echo NumberToWords::convert(21, 'ar'), "\n"; // واحد وعشرون
echo NumberToWords::convert(200, 'ar'), "\n"; // مئتان
echo NumberToWords::convert(3000, 'ar'), "\n"; // ثلاثة آلاف
echo NumberToWords::convert(2000000, 'ar'), "\n"; // مليونان
echo NumberToWords::convert(1002003, 'ar'), "\n"; // مليون وألفان وثلاثة
echo NumberToWords::convert(-7, 'ar'), "\n"; // سالب سبعة
Without options, the Arabic output is the bare counting form (masculine, nominative, no vowel marks). The range is every integer below 1027, and negative numbers start with «سالب». A larger number throws number_too_large.
When a counted noun follows the number, you can ask for gender, grammatical case, vowel marks, other spellings of «مئة» and more. The new ArabicOptions and the Arabic ordinals (first to ninety-ninth) have their own page: Arabic number words.
An unsupported locale throws UnsupportedLocaleException with the code unsupported_locale:
try {
NumberToWords::convert(5, 'en');
} catch (\RtlyKit\Exceptions\UnsupportedLocaleException $e) {
echo $e->getMessage(), "\n"; // Unsupported locale 'en' (use 'fa' or 'ar').
}
From words back to a number#
NumberToWords::fromWords() is the reverse of the Persian conversion for the forms convert() produces. It returns an int when the value fits in a PHP int, and a digit string otherwise.
var_dump(NumberToWords::fromWords('بیست و سه')); // int(23)
var_dump(NumberToWords::fromWords('منفی چهل و دو')); // int(-42)
var_dump(NumberToWords::fromWords('هزار و یک')); // int(1001)
var_dump(NumberToWords::fromWords('دو میلیون و سیصد هزار و پنج')); // int(2300005)
// Round trip across the whole range:
var_dump(NumberToWords::fromWords(NumberToWords::convert(PHP_INT_MAX)));
// int(9223372036854775807)
var_dump(NumberToWords::fromWords(NumberToWords::convert('999999999999999999999')));
// string(21) "999999999999999999999"
How words are read#
- The input is cleaned first. Arabic letter variants become Persian («ك» to «ک», «ي» to «ی»), a ZWNJ counts as a space, and extra whitespace is ignored.
- A leading «منفی» makes the result negative. «منفی صفر» is
0. - A scale word with no number before it means one, so «هزار» is 1000.
- Scales must go from large to small. «هزار هزار» and «هزار میلیون» throw.
- Inside a group the order is hundreds, then tens, then units. A single word from «ده» to «نوزده» can stand in for tens and units. «دو صد», «پنج و بیست» and «یازده و یک» throw.
- The word «و» is required between every two number words. The one pair written without it is a multiplier and its scale word, as in «دو هزار». A «و» at the start, at the end, doubled or next to a scale word is rejected.
- «صفر» is accepted only on its own, or after «منفی».
try {
NumberToWords::fromWords('یکصد');
} catch (\RtlyKit\Exceptions\InvalidNumberException $e) {
echo $e->getMessage(), ' [', $e->getErrorCode()->value, "]\n";
// Unknown number word 'یکصد'. [invalid_number_words]
}
Errors carry the code invalid_number_words (unknown word, wrong sequence, scales out of order, empty text) or input_too_long for text over 4096 bytes.
fromWords() reads only the canonical word order. A phrase like «دو صد» (which a lenient reader would turn into 102), «بیست یک» or a stray «و» at the end throws InvalidNumberException with the code invalid_number_words. Every string that convert() produces is read back unchanged, and a bare scale word at the start («هزار و یک») is allowed. Only the Persian form is read. Arabic words from convert($n, 'ar'), ordinals such as «سیام» and the compact spelling «یکصد» are not understood and throw.