【问题标题】:Javascript parse string to integerJavascript将字符串解析为整数
【发布时间】:2013-11-09 20:41:23
【问题描述】:

在 codewars 上工作我试图解决这个问题:

在这个 kata 中,我们要将字符串转换为整数。字符串仅表示单词中的数字。

例子:

  • “一”=> 1
  • “二十”=> 20
  • "246" => 246
  • “七十八万三千九百一十九” => 783919

================================================ ====================================

我想出了下面的代码来做到这一点。 On jsfiddle for you convience.

我遇到的一个问题是“七十万”给你 10700。

我花了一天的时间环顾四周并试图弄清楚这一点,但我只是卡住了。程序采取的步骤是:

  • 字符串变为“千百七” - 好
  • 第一个 while 循环找到“千”并将乘数设置为 1000 - 好
  • 第二个 while 循环找到 'hundred' 但随后 mult.exec(a[0]) if 语句解析为 null。 - 该死的

所以乘数不是变成 100000,而是值变成了 100000,我们注定会得到错误的答案。

在尝试调试时,我尝试在 jsfiddle 的 while 中创建第二个循环期间使用的数组。在那里它起作用并等同于“一百”而不是空值。有谁知道为什么会发生这种情况?

function parseInt(number) { 

    // reference array for english -> integer
    var ref = { one:1, two:2, three:3, four:4, five:5, six:6, seven:7, eight:8, nine:9, ten:10, eleven:11, twelve:12, thirteen:13, fourteen:14, fifteen:15, sixteen:16, seventeen:17, eighteen:18, nineteen:19, twenty:20, thirty: 30, forty: 40, fifty: 50, sixty: 60, seventy: 70, eighty: 80, ninety:90, hundred: 100, thousand: 1000, million: 1000000 };

    // regex to find number values from the string
    var find = new RegExp( "(one|t(wo|hree|en|welve|hirteen|wenty|hirty)|f(our|ive|ourteen|iftenn|orty|ifty)|s(ixteen|ixty|eventy|ix|even|eventeen|teen)|eigh(ty|t|teen)|nin(ety|e|eteen)|zero|hundred|thousand|million)", "gi" );

    // hundred/thousand/million etc. act as multipliers in this solution and need a seperate search
    var mult = new RegExp( "(hundred|thousand|million)", "gi" );

    // reversing the string allows us to add largest digits first
    number = number.split(' ').reverse().join(" ");

    // while there is a number in string number
    //   if that number is a multiplier
    //     if that number is 100 -> multiplier = multiplier * 100;
    //     else multiplier = reference value;
    //   else value = value + reference value * multiplier
    // end while
    value = 0; multiplier = 1;
    while( a = find.exec(number) ) {

        if( m = mult.exec(a[0]) ) {

            if( m[0] == 'hundred' ) { multiplier *= 100; }
            else { multiplier = ref[m[0]]; }

        }
        else {

            value += ref[a[0]] * multiplier;

        }

    }   
    return value;
}

【问题讨论】:

  • 这是您正在研究的一个有趣的问题,我不能说我完全理解您的代码。但是,其中有一些陷阱与您的问题没有直接关系。 1) 您可能希望避免与内置的 'parseInt' 函数发生名称冲突。它可能不会影响您的代码行为,但使用这样的内置名称可能是一种不好的做法。
  • 2) 您的 find 正则表达式没有正确防止匹配正确的前缀 - 在您的示例 JS fiddle 中,当它应该匹配“十七”时,它似乎匹配“七”作为正确的前缀。您需要在正则表达式字符串中包含空格保护以强制进行全字匹配。
  • 好主意,我将把它合并到我的法语词法分析器中,当数字变得太大时,建议用数字(int)表示代替单词(字符串)表示。虽然同意@MikeEdwards - 有些情况您可能需要注意:7 将是sevenseventeen 的结果,因为RegEx 在找到第一个有效片段时停止匹配(seven )。 4fourfourteen 也是另一个例子。您需要一种解决方法,就像他建议的那样。另外,英文中的每个数字都可以分解成30个左右的部分,这不是很有趣吗?
  • 我应该澄清一下——“这个”并不是指你的代码。我的意思是将法语文字数字表示解析为整数表示的想法,以便在文字表示在文本中“太长”时给出建议。我回头一看,发现我的措辞有点不对劲,我错过了编辑截止日期:)
  • 在 JavaScript 中,您应该始终使用正则表达式文字,除非您的正则表达式是动态的。这些似乎不是……

标签: javascript


【解决方案1】:

也许你不需要正则表达式

function parse(numbersInString){
    var ref = { one:1, two:2, three:3, four:4, five:5, six:6, seven:7, eight:8, nine:9, ten:10, eleven:11, twelve:12, thirteen:13, fourteen:14, fifteen:15, sixteen:16, seventeen:17, eighteen:18, nineteen:19, twenty:20, thirty: 30, forty: 40, fifty: 50, sixty: 60, seventy: 70, eighty: 80, ninety:90 },
        mult = { hundred: 100, thousand: 1000, million: 1000000 },
        strNums = numbersInString.split(' ').reverse(),
        number = 0,
        multiplier = 1;

    for(i in strNums){
        if( mult[strNums[i]] != undefined ) {
            if(mult[strNums[i]]==100) {
                multiplier*=mult[strNums[i]]
            }else{
                multiplier=mult[strNums[i]]
            }
        } else {
            if (!isNaN(parseFloat(strNums[i]))) {
                number += parseFloat(strNums[i]) * multiplier;
            } else {
                var nums = strNums[i].split('-');
                number += ((ref[nums[0]]||0) + (ref[nums[1]]||0)) * multiplier;
            }
        }
    }
    return number;
}

【讨论】:

  • 怎么样...完美的例子,我让问题变得比我需要的更难。非常感谢格兰迪。
【解决方案2】:

非常有趣的问题。我认为观察字符串中无论何时出现一亿、十亿、十亿等非常重要,它可能是它乘以该数字之前的所有内容,也可能是数字本身。如果是一百,可能这还没有结束。以后我们可能需要乘以另一个倍数,比如“十万”。

因此,我将总数的计算分为 3 个变量:totalOfUnitstotalOfHundredstotalOfMultitudes。然后按如下顺序修改所有数字:

  • 如果遇到小于100的数字,添加到totalOfUnits
  • 如果遇到 100:
    • 如果totalOfUnits == 0,则将 100 添加到 totalOfHundreds
    • 如果totalOfUnits > 0,则在totalOfHundreds 上加上100 * 个单位并将totalOfUnits 设置为0
  • 如果遇到其他人群:
    • 如果 totalOfUnits == 0 且数百 == 0,则将 multitude 本身添加到 totalOfMultitudes
    • 如果totalOfUnits > 0 或totalOfHundreds > 0,则将多个时间(totalOfUnits + totalOfHundreds) 添加到totalOfMultitudes 并将totalOfUnitstotalOfHundreds 设置为0。

最后,返回totalOfUnits + totalOfHundreds + totalOfMultitudes。代码适用于所有给定的示例,如下所示:

function parseNumber(num){
    var units = {
        zero:0, one:1, two:2, three:3, four:4, five:5, six:6, seven:7, eight:8, nine:9, ten:10,
        eleven:11, twelve:12, thirteen:13, fourteen:14, fifteen:15, sixteen:16, seventeen:17, eighteen:18, nineteen:19,
        twenty:20, thirty: 30, forty: 40, fifty: 50, sixty: 60, seventy: 70, eighty: 80, ninety:90
    };
    var hundreds = {
        hundred: 100
    };
    var multitudes = {
        hundred: 100,
        thousand: 1000,
        million: 1000000
    };

    var parts = num.split(/[ -]/);

    totalOfUnits = 0;
    totalOfHundreds = 0;
    totalOfMultitudes = 0;

    var result = undefined;

    for(var i = 0; i < parts.length; i++){
        if(units[parts[i]]){
            //Add unit
            totalOfUnits = totalOfUnits + units[parts[i]];
        }else if(hundreds[parts[i]]){
            totalOfHundreds += hundreds[parts[i]] * (totalOfUnits || 1);
            totalOfUnits = 0;
        }else if(multitudes[parts[i]]){
            totalOfMultitudes += multitudes[parts[i]] * (((totalOfUnits || 0) + (totalOfHundreds || 0)) || 1);
            totalOfUnits = totalOfHundreds = 0;
        }
    }

    return totalOfUnits + totalOfHundreds + totalOfMultitudes;
}

【讨论】:

  • 感谢您的建议 Borre。我喜欢把它分成三种不同类型的想法,而不仅仅是两种。干杯。
【解决方案3】:

感觉mult.exec 应该在while 块中以将所有乘数放在一起。

这个小sn-p

while( a = find.exec(number) ) {
    if( m = mult.exec(a[0]) ) {
        while(m) {
            multiplier *= ref[m[0]];
            m = mult.exec(a[0]);
        }
    }
    else {
        value += ref[a[0]] * multiplier;
    }
}   

为 70 万人做好了工作,但随后却为这个庞大的数字破坏了它。百位在number 数组和multiplier 数组中的事实可能是问题的根源,尽管我找不到确切的解决方案。

有趣的小问题。或许有了这个线索,你就可以弄清楚剩下的了。

【讨论】:

    【解决方案4】:

    这不是一个答案,但我想稍微评论一下这种方法,因为我看不出您如何使用当前算法解析单词。你可以让它适用于一个特定的实例或范围,但它永远不会适用于所有的单词变体。

    如果您在数据结构中分别计算所有类型的单元,例如,会更容易和更可预测

    var data = {
        millions:3, 
        hundredThousands:2,
        tenThousands:6, 
        thousands:6, 
        hundreds:0, 
        tens:8, 
        ones:9
    };
    

    计数后,您可以简单地将所有结果(包括零)串起来组成整数值。

    var value = [
            data.millions,
            data.hundredThousands,
            data.tenThousands,
            data.thousands,
            data.hundreds,
            data.tens,
            data.ones
        ].join('');
    
    return parseInt(value); // 3266089
    

    【讨论】:

      猜你喜欢
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 2010-10-16
      相关资源
      最近更新 更多