2013-11-09 3 views
5

Работая над на codewars я пытался решить эту проблему:Javascript разбора строки в целое

В этом ката мы хотим, чтобы преобразовать строку в целое число. Строки просто представляют числа в словах.

Примеры:

  • "один" => 1
  • "двадцать" => 20
  • "двести сорок шесть" => 246
  • «семьсот восемьдесят три тысячи девятьсот девятнадцать "=> 783919

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

Я придумал код ниже, чтобы сделать это. On jsfiddle for you convience.

Проблема я столкнулся в «семьсот тысяч» дает 10700.

Я провел целый день, глядя вокруг и пытается понять это, но я просто плоский застрял. Шаги, программа занимает:

  • строка становится «тысяча сто семь» - хороший
  • первым в то время как петля находки «Thousand» и устанавливают множитель 1000 - хороший
  • второго в то время как петля находки «сто», но то оператор mult.exec (a [0]) if имеет значение null. - damn

Таким образом, вместо множителя, становящегося 100000, значение становится 100000, и мы обречены на неправильный ответ.

При попытке отладки это я попытался создать массив, используемый во время второго цикла в то время как в jsfiddle. Там он работал и приравнивался к «сто» вместо нуля. Кто-нибудь знает, почему это произойдет?

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

Это интересная проблема, над которой вы работаете, и я не могу сказать, что полностью понимаю ваш код. Однако есть несколько ошибок, которые напрямую не связаны с вашей проблемой. 1) вы можете избежать столкновения имен со встроенной функцией parseInt. Это может не повлиять на поведение ваших кодов, но, вероятно, это плохая практика использования такого встроенного имени. –

+1

2) ваше регулярное выражение 'find' не защищает должным образом соответствующие соответствия - в вашем примере скрипт JS кажется, что он соответствует 7 символам в качестве правильного префикса, когда он должен соответствовать« семнадцать ». Вы хотите включить в строку регулярных выражений белые пробелы, чтобы принудительно выполнить полное слово. –

+1

Утонченная идея, я собираюсь включить это в свой французский лексический анализатор, чтобы предложить представление числа (int) вместо представления слова (строки), когда числа растут слишком большими. Согласовано с @MikeEdwards, хотя есть некоторые случаи, о которых вы, возможно, захотите знать: '7' будет результатом' семь' и 'семнадцать', потому что RegEx перестает сопоставлять, когда находит первую действительную часть (' seven'). '4' в' four' и 'fourteen' - еще один пример.Вам нужно обходное решение, как тот, который он предложил. Кроме того, разве не интересно, что каждое число на английском языке можно разбить на 30 или около того? –

ответ

4

может быть, вам не нужно регулярное выражение

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; 
} 
+0

Как насчет этого ... идеальный пример того, что я делаю проблему сложнее, чем она мне нужна. Большое спасибо Гранди. – MyKungFuIsGood

1

Такое ощущение, что mult.exec должен быть в while блоке, чтобы получить все мультипликаторы вместе.

Этого маленький фрагмент

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; 
    } 
} 

делает вещи работать на семьсот тысяч, но потом бюсты его для этого огромного количества. Тот факт, что сто находится в массиве number, и массив multiplier, вероятно, является корнем проблемы, хотя я не смог найти точное решение.

Увлекательная проблема. Может быть, с этой подсказкой, вы можете понять, что остальные.

-1

Это не ответ, но мне нравится комментировать подход немного, так как я не вижу, как вы могли бы разобрать слова с помощью вашего текущего алгоритма. Вы можете заставить его работать для одного конкретного экземпляра или диапазона, но он никогда не будет работать для всех вариантов слов.

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

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 
1

Очень интересная проблема. Я думаю, очень важно наблюдать, что всякий раз, когда в цепочке происходит сто миллионов, миллиард и т. Д., Это может быть либо все до того, как это число будет, либо само число. Если это сто, может быть, это даже не конец. Возможно, нам придется размножаться другим множеством позже, как в «сто тысяч».

Поэтому я разложил вычисление суммы на 3 переменные: totalOfUnits, totalOfHundreds и totalOfMultitudes. Затем пересмотреть все номера в порядке, как это:

  • Если число ниже 100 встречается, добавьте его в totalOfUnits
  • Если 100 встречается:
    • Если totalOfUnit сек == 0, Добавить 100 в totalOfHundreds
    • Если totalOfUnits> 0, добавить 100 * единиц в totalOfHundreds и установить totalOfUnits до 0
  • Если другой мульт itude встречается:
    • Если totalOfUnits == 0 и сотни == 0, добавить само множество в totalOfMultitudes
    • Если totalOfUnits> 0 или totalOfHundreds> 0, добавить множество раз (totalOfUnits + totalOfHundreds) в totalOfMultitudes и установить totalOfUnits и totalOfHundreds 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; 
} 
+0

Спасибо за ваш совет Borre. Мне нравится идея разделить его на три разных типа вместо двух. Приветствия. – MyKungFuIsGood

Смежные вопросы