Javascript 将拼写的数字(22)转换为数字(22)

Javascript 将拼写的数字(22)转换为数字(22),javascript,math,numbers,numeric,Javascript,Math,Numbers,Numeric,我正在尝试将拼写的数字字符串转换为数字/数字字符串 我设法做了相反的事情,如下所示,但当我尝试反转它时,我没有很好地工作,它返回undefined 00 undefined for'two' var th = [ "", "thousand", "million", "billion", "trillion" ]; var dg = [ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"

我正在尝试将拼写的数字字符串转换为数字/数字字符串

我设法做了相反的事情,如下所示,但当我尝试反转它时,我没有很好地工作,它返回undefined 00 undefined for'two'

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) {
            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, " ");
}
有人能帮我在javascript中扭转这种局面吗?或者给我一些建议,告诉我怎样才能完成我想做的事情

我尝试过使用解析器,但我觉得我正在定义1=1,2=2,。。。十六=16,十七=17,。。。七十三等于七十三。所以本质上是用数字对应物定义许多数字字符串。必须有更好的方法来做到这一点


ML在我脑海中闪过,但为什么要学习一些东西呢?一是1。我没有得到各种输入并试图将其与单个输出关联/匹配。例如,hello,hey,hi,以及任何类似的问候语。

幸运的是,除了十以外,英语的编号是一致的。您需要定义从“一”到“十九”的字符串,从“二十”到“九十”、“百”、“千”、“百万”等所有十个字符串

然后,对于解析器,将字符串解析为标记,基本上将其拆分。如果愿意,您可以将令牌转换为数字,如果愿意,也可以将其保留为字符串。我在这里用数字,因为它有点短

因此,如果您有一个四千八百八十五的字符串,您可以将其解析为令牌:

4 1000 100 80 5

您可以丢弃单词“and”,以及逗号和其他杂音

然后,您可以在下面非常简化的伪代码中从后面处理这个字符串

总数=0; 乘法器=1

repeat
  Number = ReadNumber || 1;
  Total += Multiplicator * Number;
  Multiplicator = ReadMultiplicator;
乘法器是10,20,30。。100, 1000, 1000000 数字是1。。19这些是可选的。如果没有找到编号,则将其视为已读取编号

因此,最后,您应该将字符串视为

4100011001805

应按以下方式处理:

5+1*80+1*100+4*1000

我说伪代码非常简单。首先,你的解析需要能够“窥视”前方。如果前面的标记不是数字,则它必须是乘法器,因此不应跳过它。 此外,您还需要一些额外的支票。毕竟,100之前的数字是特殊的。您不希望解析字符串384到244

然后你需要一些额外的图层。八万五千怎么样?看起来你不应该在一个乘法器之前只读取一个数字,但实际上所有小于该乘法器的标记都应该一起解析,所以

十六万

应该被解析为

1100 160 1000

您可以稍后在该部分中添加额外的检查,尽管您可以先不添加检查。毕竟,亿实际上是十亿,但它将正确解析,甚至给出正确的结果


所以,我认为解析正确的字符串是完全可行的。检查异常会使它变得更加困难。2300是现成的,但奇怪的是,你也可以写一万两千三百,结果是12.300。但是,我想,像这样的检查一开始并不严格需要。

如果您只需要整数,您可以使用键值对象从单个单词中构建数字-

function wordsToNumber(s){
    var w= s.toLowerCase().replace(/(thousand|[mbr]illion),?/g, '$1,');
    var n= 0, nArray= w.split(/,/), 
    sub= 0, tem, segment, 
    nwords={
        billion: 1e9, eight: 8, eighteen: 18, eighty: 80, 
        eleven: 11, fifteen: 15, fifty: 50,  five: 5, forty: 40, 
        four: 4, fourteen: 14,  hundred: 100, million: 1e6,  
        nine: 9, nineteen: 19, ninety: 90, one: 1, quadrillion: 1e15, 
        seven: 7, seventeen: 17, seventy: 70, six: 6, sixteen: 16, 
        sixty: 60, ten: 10,  thirteen: 13, thirty: 30, thousand: 1e3, 
        three: 3, trillion: 1e12,twelve: 12, twenty: 20, two: 2, zero: 0
    };
    while(nArray.length){
        sub= 0;
        segment= nArray.shift().match(/[a-z]+/g) || [];
        segment.forEach(function(w2){
            tem= nwords[w2.trim()];
            if(isFinite(tem)){
                if(tem<100) sub+= tem;
                else sub*= tem;
            }
        });
        n+= sub;
    }
    return n;
}
var str= 'twenty two thousand one hundred and fifty one';

wordsToNumber(str);

/*  returned value: (Number)
22151
*/
为了获得更多功能,您可以编写更多代码-

<!doctype html>
<html lang="en">
<head>
<meta charset= "utf-8">
<title>Number Words</title>
<style>
</style>
<script>
Math.fraction= function(n, prec, up){
    var s= String(n), 
    p= s.indexOf('.');
    if(p== -1) return s;
    var i= Math.floor(n) || '', 
    dec= s.substring(p), 
    m= prec || Math.pow(10, dec.length-1), 
    num= up=== 1? Math.ceil(dec*m): Math.round(dec*m), 
    den= m, 
    g= Math.gcd(num, den);
    if(den/g== 1) return String(i+num);
    if(i) i= i+' and  ';
    return i+ String(num/g)+'/'+String(den/g);
}
Number.fromFraction= function(str, prec){
    var rx=/(\d+)\/(\d+)/, dec= 0, I= 0, 
    M= rx.exec(str);
    if(M){
        if(M.index>0) I= parseFloat(str);
        if(M[1]) dec= M[1]/M[2];
        if(!prec) prec= str.length+1;
        if(typeof prec== 'number') dec= +(dec.toFixed(prec));
        return I+dec;
    }
    return parseFloat(str);
}
Number.fromRoman= function(s){
    s= String(s).toUpperCase();
    if(s.length>15 ||  /[^MDCLXVI]/.test(s)) return NaN;
    var L= s.length, sum= 0, i= 0, next, val, 
    R={
        M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1
    };
    while(i<L){
        val= s.charAt(i++);
        if(!R[val]) return NaN;
        val= R[val];
        next= R[(s.charAt(i) || 'N')] || 0;
        if(next>val) val*= -1;
        sum+= val;
    }
    if(sum.toRoman()== s) return sum;
    return NaN;
}
Number.prototype.toRoman= function(){
    var n= Math.floor(this), val, s= '', limit= 3999, i= 0, 
    v= [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1], 
    r= ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
    if(n<1 || n>limit) return '';
    while(i<13){
        val= v[i];
        while(n>= val){
            n-= val;
            s+= r[i];
        }
        if(n== 0) return s;
        ++i;
    }
    return '';
}
var NW={
    /* numbers to words */
    nameNumbers: function(str){
        var nw= NW.numberWords, 
        s= (str+'').replace(/([^\d])(?=\.\d+)/g, '$1 0').trim();
        var f, w= '', x, xs, n, ns, M, 
        rx=/(-?\d+)(\.(\d+)([eE]([+-]?\d+))?)?/g, 
        rx2=/(\d+)(\.(\d+)([eE]([+-]?\d+))?)?/, 
        rq=/((\d+)? +(and +)?)?(\d+)\/(\d+)/g;
        s= s.replace(rq, function(a){
            return NW.printFraction(a);
        });
        s= s.replace(rx, function(q){
            n= +q;
            ns= n+'';
            M= rx2.exec(ns) || [];
            w= (n<0)? 'minus ': '';
            if(M[1]) w+= nw(M[1]);
            if(M[3]){
                f= M[3].split('').map(function(itm){
                    return nw(itm);
                });
                w+= ' point '+ f.join(' ');
                if(M[5]){
                    x= +M[5];
                    xs= x<0? 'minus ': '';
                    xs+= NW.ordinal(nw(x));
                    w+= ' times ten to the '+xs;
                }
            }
            return w || q;
        });
        return s.replace(/ {2,}/g, ' ');
    },
    numberWords: function numberWords(x){
        var n= +x;
        if(isNaN(n) || n%1) return ''+x;
        n= Math.abs(n);
        var i= 0, p, prefix= [], num, rem, 
        NK= NW.numberwords_array, 
        w= NK[0], w1= NK[1], w2= NK[2], mag= NK[3];
        while(n>99){
            x= mag[i];
            if(n>= x){
                p= Math.floor(n/x);
                n%= x;
                prefix.push(numberWords(p)+w2[i]);
            }
            ++i;
        }
        if(prefix.length){
            prefix= prefix.join(', ');
            if(n) prefix+= ' and ';
            else return prefix;
        }
        else prefix= '';
        if(n<20) num= w[n];
        else{
            num= w1[Math.floor(n/10)];
            rem= n%10;
            if(rem) num+= ' '+w[rem];
        }
        return prefix+num;
    },
    numberwords_array: [
        ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 
        'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 
        'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'], 
        ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 
        'seventy', 'eighty', 'ninety'], 
        [' quadrillion', ' trillion', ' billion', ' million', 
        ' thousand', ' hundred'], 
        [1e15, 1e12, 1e9, 1e6, 1e3, 100]
    ], 
    ordinal: function(s){
        var ax, rx, suffix, str= ' '+s.trim();
        ax= str.lastIndexOf(' ');
        suffix= str.substring(ax).toLowerCase();
        if(str.charAt(str.length-1)== 'y'){
            return str.slice(0, -2)+'tieth';
        }
        if(ax>1) str= str.substring(0, ax);
        else str= ' ';
        switch(suffix.trim()){
            case 'one': return str+' first';
            case 'two': return str+' second';
            case 'three': return str+' third';
            case 'five': return str+' fifth';
            case 'eight': return str+' eighth';
            case 'nine': return str+' ninth';
            case 'twelve': return str+' twelfth';
            default: return str+suffix+'th';
        }
    },
    printFraction: function(str){
        var num, RN= NW.numberWords, 
        M=/((\d+) +)?(\d+) *\/ *(\d+)/g.exec(str.trim());
        if(!M) return str;
        num= M[2]? RN(M[2])+' and ': '';
        num+= RN(+M[3])+'-';
        if(M[4]=== '2') num+= 'half';
        else if(M[4]=== '4') num+= 'quarter';
        else num+= NW.ordinal(RN(+M[4]));
        if(M[3]!== '1') num+= 's';
        return num;
    },
    /* words to numbers */
    reDigit: function(n){
        var sub= [], tem, d= n.match(/[a-z]+/g), L= d.length-1, 
        nwords= NW.wordnumber_keys;
        d.map(function(w, i){
            tem= nwords[w];
            if(isFinite(tem)){
                if(tem<20 || i== L) sub.push(tem+'');
                else sub.push((tem+'').charAt(0));
            }
        });
        return sub.join('');
    },
    reFraction: function(str){
        var M, w= 0, n, d, f2= 0, prec, ax;
        ax= str.lastIndexOf(' and ');
        if(ax== -1){
            ax= 0;
            w= 'zero';
        }
        else{
            w= str.substring(0, ax);
            ax+= 4;
        }
        M= str.substring(ax).split('-');
        n= M[0];
        d= M[1];
        if(n && d){
            d= NW.wordsToNumber(d);
            n= NW.wordsToNumber(n);
            return [w, n/d];
        }
        return [w];
    },
    wordNumber: function(str){
        var n= 0, sign= 1, whole= 0, dec= 0, frac, 
        suffix= 0, exp= 1, exsign= 1, prec, pt, 
        rx1=  /(illion|thousand|hundred)/i, 
        rx2=/( +times ten to the( +minus)? +)/g, 
        rx3=/(point|times|[^a-z, ])/, 
        s= str.toLowerCase().trim().replace(/ieth?$/, 'y').replace(/(ths?|s)$/, '');
        if(s.indexOf('minus ')== 0){
            sign= -1;
            s= s.substring(5);
        }
        if(!rx3.test(s)){
            n= (!rx1.test(s))? NW.reDigit(s): NW.wordsToNumber(s);
            return n*sign;
        }
        whole= s;
        var pt= s.split('point ');
        dec= pt[1];
        if(dec){
            whole= pt[0];
            temp= rx2.exec(dec);
            if(temp!= null){
                if(temp[2]) exsign= -1;
                suffix= dec.substring(rx2.lastIndex);
                dec= dec.substring(0, temp.index);
                suffix= NW.wordsToNumber(suffix);
                exp= Math.pow(10, suffix*exsign);
            }
            dec= NW.reDigit(dec);
            prec= dec.length+1;
            dec= +('0.'+dec);
        }
        else if(whole.indexOf('-')!= -1){
            pt= NW.reFraction(whole);
            whole= pt[0];
            dec= pt[1];
        }
        n= NW.wordsToNumber(whole.replace(/ +and +/g, ' '));
        if(dec){
            n+= dec;
            if(!prec) frac= Math.min(String(n).length, 15);
            n= n.toPrecision(frac);
        }
        if(exp!== 1) return sign*((n*exp).toExponential(prec));
        return sign*n;
    },
    wordnumber_keys:{
        billion: 1e9, eigh: 8, eight: 8, eighteen: 18, eightt: 8, eighty: 80, 
        eleven: 11, fif: 5, fifteen: 15, fifty: 50, first: 1, five: 5, forty: 40, 
        four: 4, fourteen: 14, half: 2, hundred: 100, million: 1e6, nin: 9, 
        nine: 9, nineteen: 19, ninety: 90, one: 1, quadrillion: 1e15, quarter: 4, 
        second: 2, seven: 7, seventeen: 17, seventy: 70, six: 6, sixteen: 16, 
        sixty: 60, ten: 10, third: 3, thirteen: 13, thirty: 30, thousand: 1e3, 
        three: 3, trillion: 1e12, twelf: 12, twelve: 12, twenty: 20, two: 2, zero: 0
    },
    wordsToNumber: function(s){
        var w= s.toLowerCase().replace(/(thousand|[mbr]illion),?/g, '$1,');
        var n= 0, nArray= w.split(/,/), 
        sub= 0, tem, segment, 
        nwords= NW.wordnumber_keys;
        while(nArray.length){
            sub= 0;
            segment= nArray.shift().match(/[a-z]+/g) || [];
            segment.forEach(function(w2){
                tem= nwords[w2.trim()];
                if(isFinite(tem)){
                    if(tem<100) sub+= tem;
                    else sub*= tem;
                }
            });
            n+= sub;
        }
        return n;
    }
}

onload=function(){
    var nw= NW, v2= [], v;
    var A= ['150', '0.12', 'fourteen hundred and ninety two', '65 1/16', '65.0045', 
    'thirty three and one- third', '2012', '98.6', 'MCMLIX', '897456971.25', 
    '1 1/2', '12 3/4', '-9', '33 1/3', Math.PI, 'nine and three- quarters', 
    'seventy eight point six four', 'XIX', '1.1550046210e+17', '1.222e3', 'minus two hundred', 
    '4.5e-10', '3.125e-3', '1.56760e+25'].map(function(sv){
        if(/^[IVXLCDM]+$/.test(sv)) sv= Number.fromRoman(sv);
        if(/^[a-z ,-]+$/i.test(sv)){
            v2= nw.wordNumber(sv);
        }
        else v2= nw.nameNumbers(sv);
        return '<p\>'+sv+'= '+v2+'</p\>';
    });
    document.getElementById('resultset').innerHTML=A.join('\n');
}

</script>

</head>
<body>
<div id="resultset">
</div>
</body>
</html>

下面是其他答案之一的实现:

我喜欢monkeypatching是的,是的,我知道…,但它可以很容易地从这个实现中删除

变量编号\u名称={ a:10,十亿:1e9,8:8,18:18,80:80, 11:11,15:15,50:50,5:5,40:40, 四:四四:一四亿:一亿:一六, 9:9,19:19,90:90,1:1,万亿元, 七点七,十七点十七,七十点七十,六点六,十六点十六, 六十:六十,十:十,十三:十三,三十:三万,一千, 三:3,万亿:1e12,十二:12,二十:20,二:2,零:0 } Array.prototype.last=函数{ 返回此[this.length-1]; } String.prototype.toNumber=函数{ var stripped=this.toLowerCase.replace/\-\124;和/g',.split'; var numbers=stripped.mapfunctionword{returnnumber\u NAMES[word]}; 如果numbers.somefunctionnumber{returnnumber==null}返回NaN; var parseNumbers=functionnumbers{ var合计=0; var readNumber=functiondef{ 返回编号。上次<20?编号。pop:def; } var readmagnity=函数{ 返回编号.last>19?编号.pop:0; } 总计+=读取编号0; 而数字。长度{ var震级=读取震级; var子_数=[]; 而numbers.length&&numbers.last<幅值{ sub_numbers.unshiftnumbers.pop; } 变量编号=子编号。长度?ParseNumbers子编号:1; 总数+=震级*数量; } 返回总数; } 返回ParseNumbersNumber; }
221.toNumber//2201“未定义”表示您没有将代码添加到问题中:在说出来的数字中,百通常跟在和后面,就像在一百零六中一样,但当数字是偶数百时,就不是了,例如七百。@RobG我想的逻辑是一个拼写数字在一个拼写数字之前,然后将它们相乘七百就变成了7*100=700。如果是在之后,那么把它们加起来,105变成100+5,这样就不需要和了。试过谷歌吗?@user3743069-907变成了九百零七,但通常被称为九百零七。一个问题。当读取数字时,我在您的逻辑中看到,当数字未读入时,使用1,但在100和80之前读入1。为什么?为什么不是141000110018015或者实际上是4100010805?每次都在读数字,为什么会有数字呢?我知道乘以1是如何使解析的数字正确的,但是这个数字是从哪里来的,为什么来的?你只需要对乘法器之前的数字这样做,但是想想看,也许这一步根本没有必要。毕竟,你写的不是“一百”,而是“一百”,不像其他语言。不会处理像2300这样的事情,但除此之外,它很好。我没想到你用这么少的代码就能做到。非常优雅。