【问题标题】:Convert Fraction String to Decimal?将分数字符串转换为十进制?
【发布时间】:2026-01-07 15:00:01
【问题描述】:

我正在尝试创建一个 javascript 函数,该函数可以接受一个分数输入字符串,例如 '3/2' 并将其转换为十进制 - 作为字符串 '1.5' 或数字 1.5

function ratio(fraction) {
    var fraction = (fraction !== undefined) ? fraction : '1/1',
    decimal = ??????????;
    return decimal;
});

有没有办法做到这一点?

【问题讨论】:

  • eval(fraction) 当然可以,但前提是您相信自己的输入。
  • @cdhowie 在这种情况下我愿意——谢谢!
  • 请注意,有很多小数不能精确地表示为十进制数(例如 1/3),还有很多小数不能用 javascript 精确表示:0.0065 + 0.0005 = 0.006999999999999999;

标签: javascript scope fractions


【解决方案1】:

我开发了一个函数来使用可以作为整数或小数的分数传递的因子来转换值。用户输入和转换因子的格式可能不正确,因此它会检查原始值是否为数字,以及假设 /number 表示 1/number 时是否可以将转换转换为分数,或者有分子和分母,格式为 number/number。

/**
 * Convert value using conversion factor
 * @param {float} value - number to convert
 * @param {string} conversion - factor
 * @return {float} converted value
 */
function convertNumber(value, conversion) {
  try {
    let numberValue = eval(value);
    if (isNaN(numberValue)) {
      throw value + " is not a number.";
    }
    let fraction = conversion.toString();
    let divider = fraction.indexOf("/");
    let upper = 1;
    let denominator = 1;
    if (divider == -1) {
      upper = eval(fraction);
    } else {
      let split = fraction.split("/");
      if (split.length > 2) {
        throw fraction + " cannot be evaluated to a fraction.";
      } else {
        denominator = eval(split[1]);
        if (divider > 0) {
          upper = eval(split[0]);
        }
      }
    }
    let factor = upper/denominator;
    if (isNaN(factor)) {
      throw fraction + " cannot be converted to a factor.";
    }
    let result = numberValue * factor;
    if (isNaN(result)) {
      throw numberValue + " * " + factor + " is not a number.";
    }
    return result
  } catch (err) {
    let message = "Unable to convert '" + value + "' using '" + conversion + "'. " + err;
    throw message;
  }
}

【讨论】:

    【解决方案2】:

    从可读性、逐步调试的角度来看,这可能更容易理解:

    // i.e. '1/2' -> .5
    // Invalid input returns 0 so impact on upstream callers are less likely to be impacted
    function fractionToNumber(fraction = '') {
        const fractionParts = fraction.split('/');
        const numerator = fractionParts[0] || '0';
        const denominator = fractionParts[1] || '1';
        const radix = 10;
        const number = parseInt(numerator, radix) / parseInt(denominator, radix);
        const result = number || 0;
    
        return result;
    }
    

    【讨论】:

    • 此代码是一个很好的起点,具体取决于您想要使其具有多大的弹性/防御性/可预测性。此函数要求进行单元测试以断言它在您期望处理的场景中正常工作。
    【解决方案3】:

    const fractionStringToNumber = s => s.split("/").map(s => Number(s)).reduce((a, b) => a / b);
    
    console.log(fractionStringToNumber("1/2"));
    console.log(fractionStringToNumber("1/3"));
    console.log(fractionStringToNumber("3/2"));
    console.log(fractionStringToNumber("3/1"));
    console.log(fractionStringToNumber("22/7"));
    console.log(fractionStringToNumber("355 / 113"));
    console.log(fractionStringToNumber("8/4/2"));
    
    console.log(fractionStringToNumber("3")); // => 3, not "3"

    【讨论】:

      【解决方案4】:

      这也可以:

      let y = "2.9/59"
      let a = y.split('')
      let b = a.splice(a.indexOf("/"))
      console.log(parseFloat(a.join('')))
      a = parseFloat(a.join(''))
      console.log(b)
      let c = parseFloat(b.slice(1).join(''))
      let d = a/c
      console.log(d) // Answer for y fraction
      

      【讨论】:

        【解决方案5】:

        根据 MDN 更安全的 eval()

        const safeEval = (str) => {
           return Function('"use strict";return (' + str + ")")();
        }
        
        safeEval("1 1/2") // 1.5
        

        https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Do_not_ever_use_eval!

        【讨论】:

          【解决方案6】:

          聚会也有点晚了,但eval() 的替代品是Function() 工厂,安全问题较少(至少根据 MDN)。

          var fraction = "3/2";
          console.log( Function("return (" + fraction + ");")() );
          

          这将在控制台中输出结果“1.5”。

          另外作为旁注: 1 1/2 之类的混合分数不适用于 eval()Function() 的解决方案,因为它们都偶然发现了空格。 p>

          【讨论】:

            【解决方案7】:

            我创建了一个很好的函数来做到这一点,一切都基于这个问题和答案,但它会接受字符串并输出十进制值,但也会输出整数而不会出错

            https://gist.github.com/drifterz28/6971440

            function toDeci(fraction) {
                fraction = fraction.toString();
                var result,wholeNum=0, frac, deci=0;
                if(fraction.search('/') >=0){
                    if(fraction.search('-') >=0){
                        wholeNum = fraction.split('-');
                        frac = wholeNum[1];
                        wholeNum = parseInt(wholeNum,10);
                    }else{
                        frac = fraction;
                    }
                    if(fraction.search('/') >=0){
                        frac =  frac.split('/');
                        deci = parseInt(frac[0], 10) / parseInt(frac[1], 10);
                    }
                    result = wholeNum+deci;
                }else{
                    result = fraction
                }
                return result;
            }
            
            /* Testing values / examples */
            console.log('1 ',toDeci("1-7/16"));
            console.log('2 ',toDeci("5/8"));
            console.log('3 ',toDeci("3-3/16"));
            console.log('4 ',toDeci("12"));
            console.log('5 ',toDeci("12.2"));
            

            【讨论】:

              【解决方案8】:

              为时已晚,但可能会有所帮助:

              您可以使用Array.prototype.reduce 代替eval https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

              ES6

              const fractionStrToDecimal = str => str.split('/').reduce((p, c) => p / c);
              console.log(fractionStrToDecimal('1/4/2')); // Logs 0.125
              console.log(fractionStrToDecimal('3/2')); // Logs 1.5
              

              CJS

              function fractionStrToDecimal(str) {
                return str.split('/').reduce((p, c) => p / c);
              }
              console.log(fractionStrToDecimal('1/4')); // Logs 0.25
              

              [编辑] 删除了 reducer 初始值,现在该函数适用于大于 1 的分子。谢谢,James Furey。

              【讨论】:

              • 不适用于大于 1 的分子(例如 '3/2')。
              • 你是对的。刚刚删除了减速器的初始值,它现在正在工作。谢谢!
              【解决方案9】:

              函数(ES6):

              function fractionToDecimal(fraction) {
                return fraction
                  .split('/')
                  .reduce((numerator, denominator, i) =>
                    numerator / (i ? denominator : 1)
                  );
              }
              

              函数(ES6,精简):

              function fractionToDecimal(f) {
                return f.split('/').reduce((n, d, i) => n / (i ? d : 1));
              }
              

              例子:

              fractionToDecimal('1/2');     // 0.5
              fractionToDecimal('5/2');     // 2.5
              fractionToDecimal('1/2/2');   // 0.25
              fractionToDecimal('10/5/10'); // 0.2
              fractionToDecimal('0/1');     // 0
              fractionToDecimal('1/0');     // Infinity
              fractionToDecimal('cat/dog'); // NaN
              

              【讨论】:

                【解决方案10】:

                如果您不介意使用外部库,math.js 提供了一些有用的函数来将分数转换为小数以及执行小数运算。

                console.log(math.number(math.fraction("1/3"))); //returns 0.3333333333333333
                console.log(math.fraction("1/3") * 9) //returns 3
                <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.20.1/math.js"></script>

                【讨论】:

                  【解决方案11】:

                  如果您想将结果用作分数,而不仅仅是从字符串中获取答案,那么像 https://github.com/infusion/Fraction.js 这样的库可以很好地完成这项工作。

                  var f = new Fraction("3/2");
                  console.log(f.toString()); // Returns string "1.5"
                  console.log(f.valueOf()); // Returns number 1.5
                  
                  var g = new Fraction(6.5).div(.5);
                  console.log(f.toString()); // Returns string "13"
                  

                  【讨论】:

                    【解决方案12】:

                    我有一个用于处理整数、混合分数(包括 unicode 粗俗分数字符)和小数的函数。可能需要一些修饰,但它适用于我的目的(食谱成分列表解析)。

                    输入 "2 1/2""2½""2 ½""2.5" 都将返回 2.5。例子:

                    var numQty = require("numeric-quantity");
                    
                    numQty("1 1/4") === 1.25;  // true
                    numQty("3 / 4") === 0.75;  // true
                    numQty("¼" ) === 0.25;     // true
                    numQty("2½") === 2.5;      // true
                    numQty("¾") === 0.75;      // true
                    numQty("⅓") === 0.333;     // true
                    numQty("⅔") === 0.667;     // true
                    

                    它不处理的一件事是分数中的小数,例如"2.5 / 5".

                    【讨论】:

                      【解决方案13】:

                      它适用于 eval() 方法,但您可以使用 parseFloat 方法。我觉得这样更好! 不幸的是,它只适用于那种值——“12.2”而不是“5/8”,但由于你可以处理计算,我认为这是个好方法!

                      【讨论】:

                        【解决方案14】:

                        要将分数转换为小数,只需将顶部数字除以底部数字即可。 5 除以 3 将是 5/3 或 1.67。很像:

                        function decimal(top,bottom) {
                            return (top/bottom)
                        }
                        

                        希望对你有帮助,哈哈

                        【讨论】:

                          【解决方案15】:

                          由于没有人提到它,所以有一个快速而肮脏的解决方案:

                          var decimal = eval(fraction); 
                          

                          它具有正确评估各种数学字符串的好处。

                          eval("3/2")    // 1.5
                          eval("6")      // 6
                          eval("6.5/.5") // 13, works with decimals (floats)
                          eval("12 + 3") // 15, you can add subtract and multiply too
                          

                          这里的人们会很快提到使用原始 eval 的危险,但我将此作为懒人的回答提交。

                          【讨论】:

                          • +1,因为它一个简单的解决方案,并且您已经警告了危险。
                          • @Nat 这正是我在这种情况下所需要的。谢谢!
                          • 不是懒惰,这正是 eval 的意义所在 - 评估直到运行时才知道的表达式。
                          • @GiH eval 很慢,并且有潜在危险。如果用户能想办法让你在他的字符串上调用eval(),那么他就有可能用它来做XSS。
                          • @Indolering 权利。他没有警告危险。但他确实提到了相关的危险。对于危险的清单,我们都可以问谷歌叔叔,或 bing 或其他什么;)
                          【解决方案16】:

                          类似这样的:

                          bits = fraction.split("/");
                          return parseInt(bits[0],10)/parseInt(bits[1],10);
                          

                          【讨论】:

                            【解决方案17】:

                            这是执行此操作所需的最基本的最少代码:

                            var a = "3/2";
                            var split = a.split('/');
                            var result = parseInt(split[0], 10) / parseInt(split[1], 10);
                            alert(result); // alerts 1.5
                            

                            JsFiddle:http://jsfiddle.net/XS4VE/

                            需要考虑的事项:

                            • 除以零
                            • 如果用户给你一个整数而不是一个分数,或者任何其他无效的输入
                            • 四舍五入问题(例如 1/3)

                            【讨论】:

                            • 谢谢。这很漂亮。如果我需要完整的交易,我会记住这一点,但现在我只需要eval() 方法。
                            • 不需要parseInt,使用split[0]/split[1]即可。