-
Notifications
You must be signed in to change notification settings - Fork 0
/
in-words-ru.js
125 lines (117 loc) · 4.53 KB
/
in-words-ru.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* Алгоритм и реализация на PHP - http://habrahabr.ru/post/53210/
* Спасибо runcore за идею!
*/
toInRuWords = function(number) {
var gender, tens_digit, unit_digit, leading_zero_count, outputs, level,
triple, _ref, decimals, number_length;
var zero = 'ноль';
var ten = [
['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь',
'девять'],
['', 'одна', 'две', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь',
'девять']
];
var a20 = ['десять', 'одиннадцать', 'двенадцать', 'тринадцать',
'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать', 'восемнадцать',
'девятнадцать'];
var tens = ['', '', 'двадцать', 'тридцать', 'сорок', 'пятьдесят',
'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто'];
var hundred = ['', 'сто', 'двести', 'триста', 'четыреста', 'пятьсот',
'шестьсот', 'семьсот', 'восемьсот', 'девятьсот'];
var unit = [
//1 штука, 2 штуки, 5 штук, род (мужской - 0, женский - 1)
//класс десятичных
['копейка', 'копейки', 'копеек', 1],
//класс единиц
['рубль', 'рубля', 'рублей', 0],
//класс тысяч
['тысяча', 'тысячи', 'тысяч', 1],
//класс миллионов
['миллион', 'миллиона', 'миллионов', 0],
//класс миллиардов
['миллиард', 'миллиарда', 'миллиардов', 0]];
//каждый класс состоит из регистра сотен, регистра десятков и
//регистра единиц
//преобразование строки в число
if (typeof(number) === 'string') {
number = number.replace(' ', '').replace(',', '.');
if (/^\d*(\.\d*)?$/.test(number)) {
number = parseFloat(number);
} else {
return false;
}
}
//проверка типа и значения меньше 0
if (!number || typeof(number) !== 'number' || isNaN(number) || number < 0) {
return false;
}
//разбираем на целое и дробное
_ref = number.toFixed(2).split('.');
number = _ref[0];
decimals = _ref[1];
//проверка на слишком большое число
if ((leading_zero_count = (unit.length - 1) * 3 - number.length) < 0) {
return false;
}
//дополняем к числу лидирующие нули, количество цифр делаем кратно 3
leading_zero_count = leading_zero_count % 3;
number = new Array(leading_zero_count + 1).join('0') + number;
outputs = [];
number_length = number.length;
if (number > 0) {
//идем вдоль строки блоками по 3 символа
for (var i = 0; i <= number_length; i = i + 3) {
//
triple = number.substr(i, 3);
if (!(triple > 0)) {
continue;
}
level = (number_length - i) / 3;
gender = unit[level][3];
//десятки в блоке
tens_digit = number[i+1];
//единицы в блоке
unit_digit = number[i+2];
//сотни в блоке
outputs.push(hundred[number[i]]);
if (tens_digit > 1) {
outputs.push(tens[tens_digit] + ' ' + ten[gender][unit_digit]);
} else {
outputs.push(tens_digit > 0 ? a20[unit_digit]
: ten[gender][unit_digit]);
}
//не включая класс единиц измерения
if (level > 1) {
outputs.push(morph(triple,
unit[level][0], unit[level][1], unit[level][2]));
}
}
} else {
outputs.push(zero);
}
outputs.push(morph(number, unit[1][0], unit[1][1], unit[1][2]));
//дробная часть
outputs.push(decimals + ' '
+ morph(decimals, unit[0][0], unit[0][1], unit[0][2]));
//объединяем массив в строку, убираем лишние пробелы
return outputs.join(' ').replace(/ {2,}/g, ' ').trimLeft();
};
/*
* Склонение словоформы
* @ author runcore
*/
morph = function(n, f1, f2, f5) {
n = n % 100;
if (n > 10 && n < 20) {
return f5;
}
n = n % 10;
if (n > 1 && n < 5) {
return f2;
}
if (n === 1) {
return f1;
}
return f5;
};