将数学应用于字符串中的所有数字?

时间:2015-10-28 21:07:44

标签: javascript

我正在尝试制作一个烹饪食谱计算器,它基本上可以抓取所有数字并将它们分开(到目前为止)。除了划分所有数字之外,还会将小数转换为分数。这个很重要。现在,当我运行循环以查找要替换的数字时,当行上的数字大于1时,我遇到问题。如果我输入1 egg and 2 cups of milk并告诉它除以2,它将执行此操作:

first iteration:
find: 1 and replace 1 with 1/2
result: 1/2 egg and 2 cups of milk

second iteration:
find: 2 and replace 2 with 1
result: 1/1 egg and 2 cups of milk

如果您理解正确,我现在会1/1 2。为什么?因为在第二次迭代中,它会找到2并将其替换为1。我基本上需要说:

if(number != fraction)
    replace number;

我如何从我的代码中做到这一点?

JSFiddle:http://jsfiddle.net/fgzt82yk/8/
我的循环:

for(i = 0; i < content.length; i++) {
    //Finds numbers on the line
    var number = content[i].match(regex);

    //number == null if the line is empty
    if(number != null) {

        //There can be more than 1 number on each line, create a new loop
        for(j = 0; j < number.length; j++) {

            //Turns fractions into decimals
            var evalNumber = eval(number[j]);

            //Divides the number
            var divided = parseFloat(evalNumber / selection);

            //We need some kind of precision, so we won't get 0.1666667 and so on
            var precision = selection;
            if(precision == 2) {
                precision = 0;
            }

            //Turns our decimal into a fraction (or a whole-number)
            var newNum = Math.fraction(divided.toString(), precision);

            //Replaces the original number from the content[i] (whole line) with the new number/fraction
            content[i] = content[i].replace(number[j], newNum);
        }
    }
}

添加了评论,以便更清楚地说明每行的含义。这是困扰我的最后一行..我确定。

我基本上在寻找一种更好的方法将数学应用于所有数字(小数,分数,混合数等等)。到目前为止,它有点工作,但我相信有人有更好的方法做到这一点!谢谢你的期待!

2 个答案:

答案 0 :(得分:7)

对于您的用例,我认为解决方案不是要找出如何不分割已经分割的数字,而是要一次性替换所有数字。

例如,如果你有一个要求的食谱:

  • 12个鸡蛋
  • 6杯水
  • ...

并且您希望将事情减半,最后可能会将12替换为6,然后在该传递上再次替换6。 (是的,你可以做到最大到最小的数字,但是你需要一个通行证来订购所有的数字。不必要的复杂性。)

如果您还要使用正则表达式,我建议您执行类似

的操作
function fractionize(n, d) {
  var gcd = (function gcd(a, b) {
      if ( ! b) {
          return a;
      }
      return gcd(b, a % b);
  })(n ,d);
  return d == gcd ? n / d : (n > d ? Math.floor(n / d) + ' ': '') + (n % d / gcd) + '/' + (d / gcd);
}

function decimalize(decimal, precision) {
  var power = Math.pow(10, precision);
  return Math.round(decimal * power) / power;
}

function scaleRecipe(recipe, multiply, divide) {
  return recipe.replace(/((\d*\.\d+)|((\d+)\s+)?(\d+)(\s*\/\s*(\d+))?)/g, function(_, _, decimal, _, wn, n, _, d) {
    d = d || 1;
    return decimal ? decimalize(decimal * multiply / divide, decimal.match(/\d/g).length) : fractionize(((wn || 0) * d + parseInt(n)) * multiply, divide * d);
  });
}

例如:

scaleRecipe('12 eggs, 6 cups of water, 13 chickens, 4 lb rice, 17 tsp vanilla, 60g sugar, 3/4 cups chocolate chips, 2/3 lb beef, 1/5 oz secret sauce, 3 1 / 2 teaspoons salt', 1, 6)

会给你

"2 eggs, 1 cups of water, 2 1/6 chickens, 2/3 lb rice, 2 5/6 tsp vanilla, 10g sugar, 1/8 cups chocolate chips, 1/9 lb beef, 1/30 oz secret sauce, 7/12 teaspoons salt, 0.1 lb ham, 0.027 oz honey, 0.35 pint blueberries"

并且相同的食谱/8会给你

"1 1/2 eggs, 3/4 cups of water, 1 5/8 chickens, 1/2 lb rice, 2 1/8 tsp vanilla, 7 1/2g sugar, 3/32 cups chocolate chips, 1/12 lb beef, 1/40 oz secret sauce, 7/16 teaspoons salt, 0.1 lb ham, 0.02 oz honey, 0.26 pint blueberries"

您还可以使用其他逻辑来减少分数(请参阅:JS how to find the greatest common divisor)并格式化为混合数字(分别取整数和余数部分)。

复数可能是你想要考虑的另一个方面,但英语是一种棘手的语言,有许多边缘情况。 :)

答案 1 :(得分:0)

它似乎是String.prototype.replace()的工作 - 正是你已经使用过的那个。

只需将正则表达式作为第一个参数传递,然后将转换函数作为第二个参数传递,这样您就可以一次更改所有数字 - 您不必担心数字会受到两次影响