Created
October 19, 2011 20:40
-
-
Save meglio/1299598 to your computer and use it in GitHub Desktop.
PMMEDIA Task 1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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