0

Преобразование чисел в слова на JavaScript

15

Проблема с преобразованием чисел в английские слова

Я пытаюсь преобразовать числа в английские слова. Например, число 1234 должно быть преобразовано в: "one thousand two hundred thirty four".

Моя стратегия выглядит следующим образом:

  1. Разделить цифры на группы по три и поместить их в массив <code>finlOutPut</code>, начиная справа.
  2. Преобразовать каждую группу (каждую ячейку в массиве <code>finlOutPut</code>) в слова с помощью функции <code>triConvert</code>. Если все три цифры равны нулю, преобразовать их в <code>"dontAddBigSufix"</code>.
  3. Слева направо добавить 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 ответ(ов)

0

Вашу проблему уже решили, но я хочу предложить еще один способ решения для справки.

Код написан для тестирования на 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. Вы можете использовать его как основу для дальнейшей работы или модификации.

0

Ваша проблема заключается в том, что 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];
}

Это улучшит читаемость вашего кода и позволит избежать проблем с выводом.

0

Вот перевод вашего ответа в стиле 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;
}

Надеюсь, это поможет!

0

Индийская версия

Вот обновленная версия ответа @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 ). Вы можете протестировать функцию, передавая ей различные значения, как показано в последних строчках.

0

Вы можете использовать следующий альтернативный подход, чтобы преобразовать числа в текстовые строки на JavaScript:

  1. Сначала создается объект, содержащий строковые константы:
var NUMBER2TEXT = {
    ones: ['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять', 'десять', 'одиннадцать', 'двенадцать', 'тринадцать', 'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать', 'восемнадцать', 'девятнадцать'],
    tens: ['', '', 'двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто'],
    sep: ['', ' тысяча ', ' миллион ', ' миллиард ', ' триллион ', ' квадриллион ', ' квинтиллион ', ' секстиллион ']
};
  1. Вот сам код для обработки ввода и вывода:
(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/

Этот код предоставляет функциональность для преобразования чисел в текстовые представления, что может быть полезно в различных приложениях.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь