Skip to content

Instantly share code, notes, and snippets.

@meglio
Created October 19, 2011 20:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save meglio/1299598 to your computer and use it in GitHub Desktop.
Save meglio/1299598 to your computer and use it in GitHub Desktop.
PMMEDIA Task 1
<?php
header('content-type: text/html; charset: utf-8');
/**
* Created by JetBrains PhpStorm.
* User: meglio
* Date: 19.10.11
* Time: 19:51
*
* TASK 1:
*
* Write a script that will give out any numerical amount in words,
* e. g. 2355 = two thousand three hundred fifty five. Tools and resources: PHP
*/
/**
* Converts number to text (currently for 'ru' locale only).
* Can be expanded to multiple locales, understands default numbers sex (male/female).
* Works with numbers up to 10^33 (Decillion)
*
* Successfully parses formats:
* 25, -9, - 9, 8945678392232384928000002
*
* Possible improvements:
* - add support for numbers formatting: 25,456
* - add support for decimals 246.102
* - allow for notations with "+": +24, + 24
*
*
*/
class NumberWords
{
public static $names = array(
'ru' => array(
'minus' => 'минус',
'defaultSex' => 'male',
'fixed' => array(
'0' => 'ноль',
'1' => array('male' => 'один', 'female' => 'одна'),
'2' => array('male' => 'два', 'female' => 'две'),
'3' => 'три', '4' => 'четыре', '5' => 'пять', '6' => 'шесть', '7' => 'семь', '8' => 'восемь', '9' => 'девять', '10' => 'десять',
'11' => 'одиннадцать', '12' => 'двенадцать', '13' => 'тринадцать', '14' => 'четырнадцать', '15' => 'пятнадцать',
'16' => 'шестнадцать', '17' => 'семьнадцать', '18' => 'восемьнадцать', '19' => 'девятьнадцать'
),
'tens' => array(
'2' => 'двадцать', '3' => 'тридцать', '4' => 'сорок', '5' => 'пятьдесят', '6' => 'шестьдесят', '7' => 'семьдесят',
'8' => 'восемьдесят', '9' => 'девяносто'
),
'hundreds' => array(
'1' => 'сто', '2' => 'двести', '3' => 'триста', '4' => 'четыреста', '5' => 'пятьсот',
'6' => 'шестьсот', '7' => 'семьсот', '8' => 'восемьсот', '9' => 'девятьсот'
),
'powers' => array (
0 => array('sex' => 'female', 'names' => array('тысяча', 'тысячи', 'тысяч')),
1 => array('sex' => 'male', 'names' => array('миллион', 'миллиона', 'миллионов')),
2 => array('sex' => 'male', 'names' => array('миллиард', 'миллиарда', 'миллиардов')),
3 => array('sex' => 'male', 'names' => array('триллион', 'триллиона', 'триллионов')),
4 => array('sex' => 'male', 'names' => array('квадриллион', 'квадриллиона', 'квадриллионов')),
5 => array('sex' => 'male', 'names' => array('квинтиллион', 'квинтиллиона', 'квинтиллионов')),
6 => array('sex' => 'male', 'names' => array('секстиллион', 'секстиллиона', 'секстиллионов')),
7 => array('sex' => 'male', 'names' => array('септиллион', 'септиллиона', 'септиллионов')),
8 => array('sex' => 'male', 'names' => array('октиллион', 'октиллиона', 'октиллионов')),
9 => array('sex' => 'male', 'names' => array('нониллион', 'нониллиона', 'нониллионов')),
10 => array('sex' => 'male', 'names' => array('дециллион', 'дециллиона', 'дециллионов'))
)
)
);
private static function sex($config, $sex = 'male')
{
return is_array($config)? $config[$sex] : $config;
}
private static function powerVariation($n, $power, $locale)
{
if (strlen($n) > 2)
$n = substr($n, 1, 2);
$n = (int)$n;
if ($n == 1)
$ind = 0;
elseif ($n==2 || $n==3 || $n==4 || ($n > 10 && in_array(substr($n, 1, 1), array('2', '3', '4'))))
$ind = 1;
else
$ind = 2;
return self::$names[$locale]['powers'][$power]['names'][$ind];
}
private static function hundredsToWords($n, $allowZero, $sex, $locale)
{
$s =& self::$names[$locale];
$len = strlen($n);
if ($len == 1)
{
if ($n == '0' && !$allowZero)
return '';
return self::sex($s['fixed'][$n], $sex);
}
if ($len == 2)
{
$tens = substr($n, 0, 1);
if ($tens == '0')
return self::hundredsToWords(substr($n, 1, 1), $allowZero, $sex, $locale);
if ($tens == '1')
return $s['fixed'][$n];
// tens > 1
$ones = substr($n, 1, 1);
$ones = ($ones == '0')? '' : ' ' . self::sex($s['fixed'][$ones]);
return $s['tens'][$tens] . $ones;
}
// len == 3
$tensWords = self::hundredsToWords(substr($n, 1, 2), false, $sex, $locale);
$hundr = substr($n, 0, 1);
if ($hundr == '0')
return $tensWords;
return $s['hundreds'][$hundr] . ((strlen($tensWords))? ' '.$tensWords : '');
}
public static function words($num, $locale)
{
if (!isset(self::$names[$locale]))
throw new Exception('Locale not supported: '.$locale);
// Remove leading zeros and convert to string: 004, -00061
$num = preg_replace('/^(-? ?)?0+(.+)/', '$1$2', trim($num));
// Convert "minus" to word and remove minus sign
$minus = (substr($num, 0, 1) == '-')? self::$names[$locale]['minus'] : '';
if ($minus)
$num = trim(substr($num, 1));
$groups = str_split(strrev($num), 3);
$words = '';
for ($power = 0; $power < count($groups); $power++)
{
$group = strrev($groups[$power]);
$sex = $power? self::$names[$locale]['powers'][$power-1]['sex'] : self::$names[$locale]['defaultSex'];
$groupWords = self::hundredsToWords($group, !$power, $sex, $locale);
if ($power && $groupWords)
$groupWords .= ' ' . self::powerVariation($group, $power-1, $locale);
if ($words)
$words = ' ' . $words;
$words = $groupWords . ' ' . $words;
}
$words = trim($words);
if ($minus && $words && $words != self::$names[$locale]['fixed']['0'])
$words = $minus . ' ' . $words;
return $words;
}
public static function test()
{
$tests = array(0, '-0', 2, 9, 10, '012', '- 0019', 21, 47, 101, ' 129 ', 180, 700, 7001, 101225,
-290000000005, '8945678392232384928000002');
foreach ($tests as $test)
echo '['.$test.'] => '.self::words($test, 'ru').'<br/>';
}
}
NumberWords::test();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment