Преобразование чисел в слова на JavaScript
Проблема с преобразованием чисел в английские слова
Я пытаюсь преобразовать числа в английские слова. Например, число 1234 должно быть преобразовано в: "one thousand two hundred thirty four".
Моя стратегия выглядит следующим образом:
- Разделить цифры на группы по три и поместить их в массив
<code>finlOutPut</code>
, начиная справа. - Преобразовать каждую группу (каждую ячейку в массиве
<code>finlOutPut</code>
) в слова с помощью функции<code>triConvert</code>
. Если все три цифры равны нулю, преобразовать их в<code>"dontAddBigSufix"</code>
. - Слева направо добавить thousand, million, billion и т.д. Если ячейка массива
<code>finlOutPut</code>
равна<code>"dontAddBigSufix"</code>
(потому что там только нули), не добавлять слово и устанавливать ячейку в<code>" "</code>
(пустую строку).
В общем, это работает довольно хорошо, но я столкнулся с проблемой с числами, такими как 190000009, которые преобразуются в: "one hundred ninety million". Почему-то функция "забывает" последние цифры, когда много нулей.
Что я сделал не так? Где ошибка? Почему это не работает идеально?
Вот код, который я использую:
function update(){
var bigNumArry = new Array('', ' thousand', ' million', ' billion', ' trillion', ' quadrillion', ' quintillion');
var output = '';
var numString = document.getElementById('number').value;
var finlOutPut = new Array();
if (numString == '0') {
document.getElementById('container').innerHTML = 'Zero';
return;
}
if (numString == 0) {
document.getElementById('container').innerHTML = 'messeg tell to enter numbers';
return;
}
var i = numString.length;
i = i - 1;
// Разделяем число на группы по три цифры и добавляем их в массив
while (numString.length > 3) {
var triDig = new Array(3);
triDig[2] = numString.charAt(numString.length - 1);
triDig[1] = numString.charAt(numString.length - 2);
triDig[0] = numString.charAt(numString.length - 3);
var varToAdd = triDig[0] + triDig[1] + triDig[2];
finlOutPut.push(varToAdd);
i--;
numString = numString.substring(0, numString.length - 3);
}
finlOutPut.push(numString);
finlOutPut.reverse();
// Преобразуем каждую группу из трех цифр в английские слова
// Если все цифры равны нулю, функция triConvert
// возвращает строку "dontAddBigSufix"
for (j = 0; j < finlOutPut.length; j++) {
finlOutPut[j] = triConvert(parseInt(finlOutPut[j]));
}
var bigScalCntr = 0; // Счётчик для массива миллион, миллиард, триллион...
for (b = finlOutPut.length - 1; b >= 0; b--) {
if (finlOutPut[b] != "dontAddBigSufix") {
finlOutPut[b] = finlOutPut[b] + bigNumArry[bigScalCntr] + ' , ';
bigScalCntr++;
}
else {
// Заменяем строку в finlOutPut[b] с "dontAddBigSufix" на пустую строку.
finlOutPut[b] = ' ';
bigScalCntr++; // Увеличиваем счётчик
}
}
// Преобразуем массив вывода в более читаемую строку
for(n = 0; n<finlOutPut.length; n++){
output +=finlOutPut[n];
}
document.getElementById('container').innerHTML = output; // Печатаем вывод
}
// Простая функция для преобразования чисел в слова от 1 до 999
function triConvert(num){
var ones = new Array('', ' one', ' two', ' three', ' four', ' five', ' six', ' seven', ' eight', ' nine', ' ten', ' eleven', ' twelve', ' thirteen', ' fourteen', ' fifteen', ' sixteen', ' seventeen', ' eighteen', ' nineteen');
var tens = new Array('', '', ' twenty', ' thirty', ' forty', ' fifty', ' sixty', ' seventy', ' eighty', ' ninety');
var hundred = ' hundred';
var output = '';
var numString = num.toString();
if (num == 0) {
return 'dontAddBigSufix';
}
// Случай чисел от 10 до 19
if (num < 20) {
output = ones[num];
return output;
}
// Числа от 100 и выше
if (numString.length == 3) {
output = ones[parseInt(numString.charAt(0))] + hundred;
output += tens[parseInt(numString.charAt(1))];
output += ones[parseInt(numString.charAt(2))];
return output;
}
output += tens[parseInt(numString.charAt(0))];
output += ones[parseInt(numString.charAt(1))];
return output;
}
Я буду признателен за любую помощь в решении этой проблемы!
5 ответ(ов)
Вашу проблему уже решили, но я хочу предложить еще один способ решения для справки.
Код написан для тестирования на Node.js, но функции должны нормально работать и в браузере. Также данный код обрабатывает диапазон [0, 1000000], но его можно легко адаптировать для более широких диапазонов.
// фактический код для преобразования начинается здесь
var ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
var tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
var teens = ['ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
function convert_millions(num) {
if (num >= 1000000) {
return convert_millions(Math.floor(num / 1000000)) + " million " + convert_thousands(num % 1000000);
} else {
return convert_thousands(num);
}
}
function convert_thousands(num) {
if (num >= 1000) {
return convert_hundreds(Math.floor(num / 1000)) + " thousand " + convert_hundreds(num % 1000);
} else {
return convert_hundreds(num);
}
}
function convert_hundreds(num) {
if (num > 99) {
return ones[Math.floor(num / 100)] + " hundred " + convert_tens(num % 100);
} else {
return convert_tens(num);
}
}
function convert_tens(num) {
if (num < 10) return ones[num];
else if (num >= 10 && num < 20) return teens[num - 10];
else {
return tens[Math.floor(num / 10)] + " " + ones[num % 10];
}
}
function convert(num) {
if (num == 0) return "zero";
else return convert_millions(num);
}
// конец кода преобразования
// код для тестирования начинается здесь
function main() {
var cases = [0, 1, 2, 7, 10, 11, 12, 13, 15, 19, 20, 21, 25, 29, 30, 35, 50, 55, 69, 70, 99, 100, 101, 119, 510, 900, 1000, 5001, 5019, 5555, 10000, 11000, 100000, 199001, 1000000, 1111111, 190000009];
for (var i = 0; i < cases.length; i++) {
console.log(cases[i] + ": " + convert(cases[i]));
}
}
main();
Этот код предоставляет функцию convert
, которая переводит числа в текстовый формат для диапазона от 0 до 1000000. Вы можете использовать его как основу для дальнейшей работы или модификации.
Ваша проблема заключается в том, что JavaScript интерпретирует группу из трех цифр с ведущим нулем как восьмеричное число. Когда эта группа ноль, результат будет одинаковым независимо от системы счисления (восьмеричной или десятичной).
Однако при вводе '009' (или '008') это становится недопустимым восьмеричным числом, и вы получаете в результате ноль.
Если бы вы проверили полный набор чисел от 190,000,001 до 190,000,010, вы бы увидели, что JavaScript пропустил '...,008' и '...,009', но выдал 'восемь' для '...,010'. Вот это и есть ваш момент "Эврика!".
Чтобы исправить ситуацию, измените ваш код:
Старый код:
for (j = 0; j < finlOutPut.length; j++) {
finlOutPut[j] = triConvert(parseInt(finlOutPut[j]));
}
На новый:
for (j = 0; j < finlOutPut.length; j++) {
finlOutPut[j] = triConvert(parseInt(finlOutPut[j], 10)); // Указываем систему счисления
}
Также у вас была проблема с добавлением запятых после каждой ненулевой группы, и вы нашли правильное место для их вставки.
Старый код для добавления запятых:
for (b = finlOutPut.length - 1; b >= 0; b--) {
if (finlOutPut[b] != "dontAddBigSufix") {
finlOutPut[b] = finlOutPut[b] + bigNumArry[bigScalCntr] + ' , ';
bigScalCntr++;
}
else {
// Заменяем строку в finlOutPut[b] с "dontAddBigSufix" на пустую строку
finlOutPut[b] = ' ';
bigScalCntr++; // Увеличиваем счетчик
}
}
// Преобразовываем выходной массив в более читаемую строку
for (n = 0; n < finlOutPut.length; n++) {
output += finlOutPut[n];
}
Теперь обновленный код:
for (b = finlOutPut.length - 1; b >= 0; b--) {
if (finlOutPut[b] != "dontAddBigSufix") {
finlOutPut[b] = finlOutPut[b] + bigNumArry[bigScalCntr]; // Убираем запятую здесь
bigScalCntr++;
}
else {
// Заменяем строку в finlOutPut[b] с "dontAddBigSufix" на пустую строку
finlOutPut[b] = ' ';
bigScalCntr++; // Увеличиваем счетчик
}
}
// Преобразовываем выходной массив в более читаемую строку
var nonzero = false; // Флаг для отслеживания ненулевых значений
for (n = 0; n < finlOutPut.length; n++) {
if (finlOutPut[n] != ' ') { // Проверяем на пустую строку
if (nonzero) output += ' , '; // Добавляем запятую перед ненулевыми значениями
nonzero = true; // Устанавливаем флаг
}
output += finlOutPut[n];
}
Это улучшит читаемость вашего кода и позволит избежать проблем с выводом.
Вот перевод вашего ответа в стиле StackOverflow на русский язык:
Знаю, что эта проблема была решена 3 года назад. Я публикую это ОСОБЕННО ДЛЯ ИНДИЙСКИХ РАЗРАБОТОК.
После того как я провел некоторое время, гугля, и экспериментируя с кодом других, я сделал быстрое решение и универсальную функцию, которая хорошо работает для чисел до 99,99,99,999. Используйте: number2text(1234.56);
, и она вернет ОДНА ТЫСЯЧА ДВЕСТИ ТРИДЦАТЬ ЧЕТЫРЕ РУПИИ И ПЯТЬДЕСЯТ ШЕСТЬ ПАЙСОВ ТОЛЬКО
. Удачи!
function number2text(value) {
var fraction = Math.round(frac(value) * 100);
var f_text = "";
if (fraction > 0) {
f_text = "И " + convert_number(fraction) + " ПАЙСА";
}
return convert_number(value) + " РУПИЯ " + f_text + " ТОЛЬКО";
}
function frac(f) {
return f % 1;
}
function convert_number(number) {
if ((number < 0) || (number > 999999999)) {
return "ЧИСЛО ЗА ПРЕДЕЛАМИ ДИАПАЗОНА!";
}
var Gn = Math.floor(number / 10000000); /* Крора */
number -= Gn * 10000000;
var kn = Math.floor(number / 100000); /* Лак */
number -= kn * 100000;
var Hn = Math.floor(number / 1000); /* Тысяча */
number -= Hn * 1000;
var Dn = Math.floor(number / 100); /* Десятки */
number = number % 100; /* Единицы */
var tn = Math.floor(number / 10);
var one = Math.floor(number % 10);
var res = "";
if (Gn > 0) {
res += (convert_number(Gn) + " КРОРА");
}
if (kn > 0) {
res += (((res == "") ? "" : " ") +
convert_number(kn) + " ЛАК");
}
if (Hn > 0) {
res += (((res == "") ? "" : " ") +
convert_number(Hn) + " ТЫСЯЧА");
}
if (Dn) {
res += (((res == "") ? "" : " ") +
convert_number(Dn) + " СТО");
}
var ones = Array("", "ОДИН", "ДВА", "ТРИ", "ЧЕТЫРЕ", "ПЯТЬ", "ШЕСТЬ", "СЕМЬ", "ВОСЕМЬ", "ДЕВЯТЬ", "ДЕСЯТЬ", "ОДИННАДЦАТЬ", "ДВЕНАДЦАТЬ", "ТРИНАДЦАТЬ", "ЧЕТЫРНАДЦАТЬ", "ПЯТНАДЦАТЬ", "ШЕСТНАДЦАТЬ", "СЕМНАДЦАТЬ", "ВОСЕМНАДЦАТЬ", "ДЕВЯТНАДЦАТЬ");
var tens = Array("", "", "ДВАДЦАТЬ", "ТРИДЦАТЬ", "СОРок", "ПЯТЬДЕСЯТ", "ШЕСТЬДЕСЯТ", "СЕМЬДЕСЯТ", "ВОСЕМЬДЕСЯТ", "ДЕВЯНОСТО");
if (tn > 0 || one > 0) {
if (!(res == "")) {
res += " И ";
}
if (tn < 2) {
res += ones[tn * 10 + one];
} else {
res += tens[tn];
if (one > 0) {
res += ("-" + ones[one]);
}
}
}
if (res == "") {
res = "ноль";
}
return res;
}
Надеюсь, это поможет!
Индийская версия
Вот обновленная версия ответа @jasonhao для индийской валюты:
function intToEnglish(number) {
var NS = [
{ value: 10000000, str: "Crore" },
{ value: 100000, str: "Lakh" },
{ value: 1000, str: "Thousand" },
{ value: 100, str: "Hundred" },
{ value: 90, str: "Ninety" },
{ value: 80, str: "Eighty" },
{ value: 70, str: "Seventy" },
{ value: 60, str: "Sixty" },
{ value: 50, str: "Fifty" },
{ value: 40, str: "Forty" },
{ value: 30, str: "Thirty" },
{ value: 20, str: "Twenty" },
{ value: 19, str: "Nineteen" },
{ value: 18, str: "Eighteen" },
{ value: 17, str: "Seventeen" },
{ value: 16, str: "Sixteen" },
{ value: 15, str: "Fifteen" },
{ value: 14, str: "Fourteen" },
{ value: 13, str: "Thirteen" },
{ value: 12, str: "Twelve" },
{ value: 11, str: "Eleven" },
{ value: 10, str: "Ten" },
{ value: 9, str: "Nine" },
{ value: 8, str: "Eight" },
{ value: 7, str: "Seven" },
{ value: 6, str: "Six" },
{ value: 5, str: "Five" },
{ value: 4, str: "Four" },
{ value: 3, str: "Three" },
{ value: 2, str: "Two" },
{ value: 1, str: "One" }
];
var result = '';
for (var n of NS) {
if (number >= n.value) {
if (number <= 99) {
result += n.str;
number -= n.value;
if (number > 0) result += ' ';
} else {
var t = Math.floor(number / n.value);
var d = number % n.value;
if (d > 0) {
return intToEnglish(t) + ' ' + n.str + ' ' + intToEnglish(d);
} else {
return intToEnglish(t) + ' ' + n.str;
}
}
}
}
return result;
}
console.log(intToEnglish(99))
console.log(intToEnglish(991199))
console.log(intToEnglish(123456799))
Этот код принимает числовое значение и преобразует его в строку на английском языке с использованием индийской системы счисления. Основные единицы — "Crore" ( crore ) и "Lakh" ( lakh ). Вы можете протестировать функцию, передавая ей различные значения, как показано в последних строчках.
Вы можете использовать следующий альтернативный подход, чтобы преобразовать числа в текстовые строки на JavaScript:
- Сначала создается объект, содержащий строковые константы:
var NUMBER2TEXT = {
ones: ['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять', 'десять', 'одиннадцать', 'двенадцать', 'тринадцать', 'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать', 'восемнадцать', 'девятнадцать'],
tens: ['', '', 'двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто'],
sep: ['', ' тысяча ', ' миллион ', ' миллиард ', ' триллион ', ' квадриллион ', ' квинтиллион ', ' секстиллион ']
};
- Вот сам код для обработки ввода и вывода:
(function( ones, tens, sep ) {
var input = document.getElementById( 'input' ),
output = document.getElementById( 'output' );
input.onkeyup = function() {
var val = this.value,
arr = [],
str = '',
i = 0;
if ( val.length === 0 ) {
output.textContent = 'Пожалуйста, введите число в текстовое поле.';
return;
}
val = parseInt( val, 10 );
if ( isNaN( val ) ) {
output.textContent = 'Неверный ввод.';
return;
}
while ( val ) {
arr.push( val % 1000 );
val = parseInt( val / 1000, 10 );
}
while ( arr.length ) {
str = (function( a ) {
var x = Math.floor( a / 100 ),
y = Math.floor( a / 10 ) % 10,
z = a % 10;
return ( x > 0 ? ones[x] + ' сто ' : '' ) +
( y >= 2 ? tens[y] + ' ' + ones[z] : ones[10*y + z] );
})( arr.shift() ) + sep[i++] + str;
}
output.textContent = str;
};
})( NUMBER2TEXT.ones, NUMBER2TEXT.tens, NUMBER2TEXT.sep );
Демо в реальном времени: http://jsfiddle.net/j5kdG/
Этот код предоставляет функциональность для преобразования чисел в текстовые представления, что может быть полезно в различных приложениях.
Как форматировать число с запятыми в качестве разделителей тысяч?
Проверка десятичных чисел в JavaScript - IsNumeric()
Как лучше всего преобразовать число в строку в JavaScript?
Как проверить, является ли число целым или с плавающей запятой?
Как извлечь число из строки в JavaScript?