113 votes

Transformer les nombres en mots dans le système lakh / crore

Je suis en train d'écrire un code qui convertit un nombre donné en mots, voici ce que j'ai obtenu après avoir cherché sur Google. Mais je pense que c'est un peu trop long pour une tâche aussi simple. Deux expressions régulières et deux for les boucles, je veux quelque chose de plus simple.

J'essaie d'y parvenir avec le moins de lignes de code possible. Voici ce que j'ai trouvé jusqu'à présent :

Des suggestions ?

var th = ['','thousand','million', 'billion','trillion'];
var dg = ['zero','one','two','three','four', 'five','six','seven','eight','nine'];
 var tn = ['ten','eleven','twelve','thirteen', 'fourteen','fifteen','sixteen', 'seventeen','eighteen','nineteen'];
 var tw = ['twenty','thirty','forty','fifty', 'sixty','seventy','eighty','ninety'];

function toWords(s) {
    s = s.toString();
    s = s.replace(/[\, ]/g,'');
    if (s != parseFloat(s)) return 'not a number';
    var x = s.indexOf('.');
    if (x == -1)
        x = s.length;
    if (x > 15)
        return 'too big';
    var n = s.split(''); 
    var str = '';
    var sk = 0;
    for (var i=0;   i < x;  i++) {
        if ((x-i)%3==2) { 
            if (n[i] == '1') {
                str += tn[Number(n[i+1])] + ' ';
                i++;
                sk=1;
            } else if (n[i]!=0) {
                str += tw[n[i]-2] + ' ';
                sk=1;
            }
        } else if (n[i]!=0) { // 0235
            str += dg[n[i]] +' ';
            if ((x-i)%3==0) str += 'hundred ';
            sk=1;
        }
        if ((x-i)%3==1) {
            if (sk)
                str += th[(x-i-1)/3] + ' ';
            sk=0;
        }
    }

    if (x != s.length) {
        var y = s.length;
        str += 'point ';
        for (var i=x+1; i<y; i++)
            str += dg[n[i]] +' ';
    }
    return str.replace(/\s+/g,' ');
}

En outre, le code ci-dessus convertit le système de numérotation anglais comme Million/Billion, j'ai besoin du système de numérotation sud-asiatique, comme dans Lakhs et Crores.

176voto

Салман Points 2057

Mise à jour : On dirait que c'est plus utile que je ne le pensais. Je viens de le publier sur npm. https://www.npmjs.com/package/num-words


Voici un code plus court, avec une RegEx et sans boucles, qui convertit comme vous le souhaitiez, dans le système de numérotation de l'Asie du Sud.

var a = ['','one ','two ','three ','four ', 'five ','six ','seven ','eight ','nine ','ten ','eleven ','twelve ','thirteen ','fourteen ','fifteen ','sixteen ','seventeen ','eighteen ','nineteen '];
var b = ['', '', 'twenty','thirty','forty','fifty', 'sixty','seventy','eighty','ninety'];

function inWords (num) {
    if ((num = num.toString()).length > 9) return 'overflow';
    n = ('000000000' + num).substr(-9).match(/^(\d{2})(\d{2})(\d{2})(\d{1})(\d{2})$/);
    if (!n) return; var str = '';
    str += (n[1] != 0) ? (a[Number(n[1])] || b[n[1][0]] + ' ' + a[n[1][1]]) + 'crore ' : '';
    str += (n[2] != 0) ? (a[Number(n[2])] || b[n[2][0]] + ' ' + a[n[2][1]]) + 'lakh ' : '';
    str += (n[3] != 0) ? (a[Number(n[3])] || b[n[3][0]] + ' ' + a[n[3][1]]) + 'thousand ' : '';
    str += (n[4] != 0) ? (a[Number(n[4])] || b[n[4][0]] + ' ' + a[n[4][1]]) + 'hundred ' : '';
    str += (n[5] != 0) ? ((str != '') ? 'and ' : '') + (a[Number(n[5])] || b[n[5][0]] + ' ' + a[n[5][1]]) + 'only ' : '';
    return str;
}

document.getElementById('number').onkeyup = function () {
    document.getElementById('words').innerHTML = inWords(document.getElementById('number').value);
};

<span id="words"></span>
<input id="number" type="text" />

La seule limitation est que vous pouvez convertir un maximum de 9 chiffres, ce qui, je pense, est plus que suffisant dans la plupart des cas .

40voto

naomik Points 10423

" Deceptivement simple tâche." - Potatoswatter

En effet. Il y a beaucoup de petits diables qui traînent dans les détails de ce problème. C'était très amusant à résoudre.

EDIT : Cette mise à jour adopte une approche beaucoup plus compositionnelle. Auparavant, il y avait une grande fonction qui enveloppait quelques autres fonctions propriétaires. Au lieu de cela, cette fois-ci, nous définissons des fonctions génériques réutilisables qui peuvent être utilisées pour de nombreuses variétés de tâches. Vous en saurez plus à ce sujet après avoir jeté un coup d'œil à numToWords lui-même

// numToWords :: (Number a, String a) => a -> String
let numToWords = n => {
  let a = [
    '', 'one', 'two', 'three', 'four',
    'five', 'six', 'seven', 'eight', 'nine',
    'ten', 'eleven', 'twelve', 'thirteen', 'fourteen',
    'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'
  ];
  let b = [
    '', '', 'twenty', 'thirty', 'forty',
    'fifty', 'sixty', 'seventy', 'eighty', 'ninety'
  ];
  let g = [
    '', 'thousand', 'million', 'billion', 'trillion', 'quadrillion',
    'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion'
  ];
  // this part is really nasty still
  // it might edit this again later to show how Monoids could fix this up
  let makeGroup = ([ones,tens,huns]) => {
    return [
      num(huns) === 0 ? '' : a[huns] + ' hundred ',
      num(ones) === 0 ? b[tens] : b[tens] && b[tens] + '-' || '',
      a[tens+ones] || a[ones]
    ].join('');
  };
  // "thousands" constructor; no real good names for this, i guess
  let thousand = (group,i) => group === '' ? group : `${group} ${g[i]}`;
  // execute !
  if (typeof n === 'number') return numToWords(String(n));
  if (n === '0')             return 'zero';
  return comp (chunk(3)) (reverse) (arr(n))
    .map(makeGroup)
    .map(thousand)
    .filter(comp(not)(isEmpty))
    .reverse()
    .join(' ');
};

Voici les dépendances :

Vous remarquerez qu'ils ne nécessitent pratiquement aucune documentation, car leurs intentions sont immédiatement claires. chunk est peut-être la seule qui prend un moment à digérer, mais ce n'est vraiment pas si mal. De plus, le nom de la fonction nous donne une bonne indication de ce qu'elle fait, et c'est probablement une fonction que nous avons déjà rencontrée.

const arr = x => Array.from(x);
const num = x => Number(x) || 0;
const str = x => String(x);
const isEmpty = xs => xs.length === 0;
const take = n => xs => xs.slice(0,n);
const drop = n => xs => xs.slice(n);
const reverse = xs => xs.slice(0).reverse();
const comp = f => g => x => f (g (x));
const not = x => !x;
const chunk = n => xs =>
  isEmpty(xs) ? [] : [take(n)(xs), ...chunk (n) (drop (n) (xs))];

"Alors, c'est mieux comme ça ?"

Regardez comment le code a été nettoyé de manière significative.

// NEW CODE (truncated)
return comp (chunk(3)) (reverse) (arr(n))
    .map(makeGroup)
    .map(thousand)
    .filter(comp(not)(isEmpty))
    .reverse()
    .join(' ');

// OLD CODE (truncated)
let grp = n => ('000' + n).substr(-3);
let rem = n => n.substr(0, n.length - 3);
let cons = xs => x => g => x ? [x, g && ' ' + g || '', ' ', xs].join('') : xs;
let iter = str => i => x => r => {
  if (x === '000' && r.length === 0) return str;
  return iter(cons(str)(fmt(x))(g[i]))
             (i+1)
             (grp(r))
             (rem(r));
};
return iter('')(0)(grp(String(n)))(rem(String(n)));

Plus important encore, les fonctions utilitaires que nous avons ajoutées dans le nouveau code peuvent être utilisées à d'autres endroits dans votre application. Cela signifie que, comme effet secondaire de l'implémentation de la fonction numToWords de cette façon, nous obtenons les autres fonctions gratuitement. Bonus soda !

Quelques tests

console.log(numToWords(11009));
//=> eleven thousand nine

console.log(numToWords(10000001));
//=> ten million one 

console.log(numToWords(987));
//=> nine hundred eighty-seven

console.log(numToWords(1015));
//=> one thousand fifteen

console.log(numToWords(55111222333));
//=> fifty-five billion one hundred eleven million two hundred 
//   twenty-two thousand three hundred thirty-three

console.log(numToWords("999999999999999999999991"));
//=> nine hundred ninety-nine sextillion nine hundred ninety-nine
//   quintillion nine hundred ninety-nine quadrillion nine hundred
//   ninety-nine trillion nine hundred ninety-nine billion nine
//   hundred ninety-nine million nine hundred ninety-nine thousand
//   nine hundred ninety-one

console.log(numToWords(6000753512));
//=> six billion seven hundred fifty-three thousand five hundred
//   twelve 

Démonstration exécutable

const arr = x => Array.from(x);
const num = x => Number(x) || 0;
const str = x => String(x);
const isEmpty = xs => xs.length === 0;
const take = n => xs => xs.slice(0,n);
const drop = n => xs => xs.slice(n);
const reverse = xs => xs.slice(0).reverse();
const comp = f => g => x => f (g (x));
const not = x => !x;
const chunk = n => xs =>
  isEmpty(xs) ? [] : [take(n)(xs), ...chunk (n) (drop (n) (xs))];

// numToWords :: (Number a, String a) => a -> String
let numToWords = n => {

  let a = [
    '', 'one', 'two', 'three', 'four',
    'five', 'six', 'seven', 'eight', 'nine',
    'ten', 'eleven', 'twelve', 'thirteen', 'fourteen',
    'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'
  ];

  let b = [
    '', '', 'twenty', 'thirty', 'forty',
    'fifty', 'sixty', 'seventy', 'eighty', 'ninety'
  ];

  let g = [
    '', 'thousand', 'million', 'billion', 'trillion', 'quadrillion',
    'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion'
  ];

  // this part is really nasty still
  // it might edit this again later to show how Monoids could fix this up
  let makeGroup = ([ones,tens,huns]) => {
    return [
      num(huns) === 0 ? '' : a[huns] + ' hundred ',
      num(ones) === 0 ? b[tens] : b[tens] && b[tens] + '-' || '',
      a[tens+ones] || a[ones]
    ].join('');
  };

  let thousand = (group,i) => group === '' ? group : `${group} ${g[i]}`;

  if (typeof n === 'number')
    return numToWords(String(n));
  else if (n === '0')
    return 'zero';
  else
    return comp (chunk(3)) (reverse) (arr(n))
      .map(makeGroup)
      .map(thousand)
      .filter(comp(not)(isEmpty))
      .reverse()
      .join(' ');
};

console.log(numToWords(11009));
//=> eleven thousand nine

console.log(numToWords(10000001));
//=> ten million one 

console.log(numToWords(987));
//=> nine hundred eighty-seven

console.log(numToWords(1015));
//=> one thousand fifteen

console.log(numToWords(55111222333));
//=> fifty-five billion one hundred eleven million two hundred 
//   twenty-two thousand three hundred thirty-three

console.log(numToWords("999999999999999999999991"));
//=> nine hundred ninety-nine sextillion nine hundred ninety-nine
//   quintillion nine hundred ninety-nine quadrillion nine hundred
//   ninety-nine trillion nine hundred ninety-nine billion nine
//   hundred ninety-nine million nine hundred ninety-nine thousand
//   nine hundred ninety-one

console.log(numToWords(6000753512));
//=> six billion seven hundred fifty-three thousand five hundred
//   twelve

Vous pouvez transpiler le code en utilisant babel.js si vous voulez voir la variante ES5

18voto

McShaman Points 470

J'ai passé un certain temps à développer une meilleure solution à ce problème. Elle peut gérer de très grands nombres, mais dès qu'ils dépassent 16 chiffres, il faut les transmettre sous forme de chaîne. Il s'agit de la limite des nombres JavaScript.

    function numberToEnglish( n ) {

        var string = n.toString(), units, tens, scales, start, end, chunks, chunksLen, chunk, ints, i, word, words, and = 'and';

        /* Remove spaces and commas */
        string = string.replace(/[, ]/g,"");

        /* Is number zero? */
        if( parseInt( string ) === 0 ) {
            return 'zero';
        }

        /* Array of units as words */
        units = [ '', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen' ];

        /* Array of tens as words */
        tens = [ '', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' ];

        /* Array of scales as words */
        scales = [ '', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quatttuor-decillion', 'quindecillion', 'sexdecillion', 'septen-decillion', 'octodecillion', 'novemdecillion', 'vigintillion', 'centillion' ];

        /* Split user argument into 3 digit chunks from right to left */
        start = string.length;
        chunks = [];
        while( start > 0 ) {
            end = start;
            chunks.push( string.slice( ( start = Math.max( 0, start - 3 ) ), end ) );
        }

        /* Check if function has enough scale words to be able to stringify the user argument */
        chunksLen = chunks.length;
        if( chunksLen > scales.length ) {
            return '';
        }

        /* Stringify each integer in each chunk */
        words = [];
        for( i = 0; i < chunksLen; i++ ) {

            chunk = parseInt( chunks[i] );

            if( chunk ) {

                /* Split chunk into array of individual integers */
                ints = chunks[i].split( '' ).reverse().map( parseFloat );

                /* If tens integer is 1, i.e. 10, then add 10 to units integer */
                if( ints[1] === 1 ) {
                    ints[0] += 10;
                }

                /* Add scale word if chunk is not zero and array item exists */
                if( ( word = scales[i] ) ) {
                    words.push( word );
                }

                /* Add unit word if array item exists */
                if( ( word = units[ ints[0] ] ) ) {
                    words.push( word );
                }

                /* Add tens word if array item exists */
                if( ( word = tens[ ints[1] ] ) ) {
                    words.push( word );
                }

                /* Add 'and' string after units or tens integer if: */
                if( ints[0] || ints[1] ) {

                    /* Chunk has a hundreds integer or chunk is the first of multiple chunks */
                    if( ints[2] || ! i && chunksLen ) {
                        words.push( and );
                    }

                }

                /* Add hundreds word if array item exists */
                if( ( word = units[ ints[2] ] ) ) {
                    words.push( word + ' hundred' );
                }

            }

        }

        return words.reverse().join( ' ' );

    }

// - - - - - Tests - - - - - -
function test(v) {
  var sep = ('string'==typeof v)?'"':'';
  console.log("numberToEnglish("+sep + v.toString() + sep+") = "+numberToEnglish(v));
}
test(2);
test(721);
test(13463);
test(1000001);
test("21,683,200,000,621,384");

11voto

Juan Gaitán Points 438

Tu devrais essayer de le faire de manière récursive. Il fonctionne pour les nombres compris entre 0 et 999999. Gardez à l'esprit que (~~) fait la même chose que Math.floor

var num = "zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split(" ");
var tens = "twenty thirty forty fifty sixty seventy eighty ninety".split(" ");

function number2words(n){
    if (n < 20) return num[n];
    var digit = n%10;
    if (n < 100) return tens[~~(n/10)-2] + (digit? "-" + num[digit]: "");
    if (n < 1000) return num[~~(n/100)] +" hundred" + (n%100 == 0? "": " " + number2words(n%100));
    return number2words(~~(n/1000)) + " thousand" + (n%1000 != 0? " " + number2words(n%1000): "");
}

8voto

Ben E Points 96

J'aime le résultat que j'ai obtenu ici, qui me semble facile à lire et suffisamment court pour être utilisé comme solution.

function NumInWords (number) {
  const first = ['','one ','two ','three ','four ', 'five ','six ','seven ','eight ','nine ','ten ','eleven ','twelve ','thirteen ','fourteen ','fifteen ','sixteen ','seventeen ','eighteen ','nineteen '];
  const tens = ['', '', 'twenty','thirty','forty','fifty', 'sixty','seventy','eighty','ninety'];
  const mad = ['', 'thousand', 'million', 'billion', 'trillion'];
  let word = '';

  for (let i = 0; i < mad.length; i++) {
    let tempNumber = number%(100*Math.pow(1000,i));
    if (Math.floor(tempNumber/Math.pow(1000,i)) !== 0) {
      if (Math.floor(tempNumber/Math.pow(1000,i)) < 20) {
        word = first[Math.floor(tempNumber/Math.pow(1000,i))] + mad[i] + ' ' + word;
      } else {
        word = tens[Math.floor(tempNumber/(10*Math.pow(1000,i)))] + '-' + first[Math.floor(tempNumber/Math.pow(1000,i))%10] + mad[i] + ' ' + word;
      }
    }

    tempNumber = number%(Math.pow(1000,i+1));
    if (Math.floor(tempNumber/(100*Math.pow(1000,i))) !== 0) word = first[Math.floor(tempNumber/(100*Math.pow(1000,i)))] + 'hunderd ' + word;
  }
    return word;
}

console.log(NumInWords(89754697976431))

Et le résultat est :

quatre-vingt-neuf mille milliards sept cent cinquante-quatre milliards six cent quatre-vingt-dix-sept millions neuf cent soixante-seize mille quatre cent trente et un

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X