Javascript:如何获取*字符串*数字的小数位数?

57
我有一组带小数点的字符串数字,例如:23.4569.450123.01... 我需要知道每个数字的小数位数,已知它们至少有1个小数位。
换句话说,retr_dec()方法应返回以下内容:
retr_dec("23.456") -> 3
retr_dec("9.450")  -> 3
retr_dec("123.01") -> 2

在这种情况下,尾随零确实算作小数,与相关问题不同。是否有一种简单/交付的方法可以在Javascript中实现这一点,或者我应该计算小数点位置并计算与字符串长度的差异?谢谢。
12个回答

117
function decimalPlaces(num) {
  var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
  if (!match) { return 0; }
  return Math.max(
       0,
       // Number of digits right of decimal point.
       (match[1] ? match[1].length : 0)
       // Adjust for scientific notation.
       - (match[2] ? +match[2] : 0));
}
额外的复杂性在于处理科学计数法,因此
decimalPlaces('.05')
2
decimalPlaces('.5')
1
decimalPlaces('1')
0
decimalPlaces('25e-100')
100
decimalPlaces('2.5e-99')
100
decimalPlaces('.5e1')
0
decimalPlaces('.25e1')
1

请注意,OP已经说明它不是一个数字,而是一个包含数字的字符串。 - Phrogz
1
@Phrogz,我认为这并不影响我的答案的有效性,只是也许我不应该计算\。(\d+)末尾的0。 - Mike Samuel
1.00 返回 0 :(,而不是 2 - arod
2
@arod, decimalPlaces("1.00") === 2 但是 decimalPlaces(1.00) === 0 因为 ("" + 1.00) === "1"。该函数操作数字的字符串表示,而不是原始数值,因为原始数值并不固有地是十进制——IEEE 854没有被纳入EcmaScript 5 - Mike Samuel
这不是你回答过的那个问题的重复吗?(https://dev59.com/_Gkw5IYBdhLWcg3w9vF-) - Dan Dascalescu
显示剩余3条评论

59
function retr_dec(num) {
  return (num.split('.')[1] || []).length;
}

4
感谢@Deleteman指出了“至少有1位小数”的要求。 - Andrew
这对于以指数表示的非常小的数字无法正常工作。 - Mike Samuel
3
很好用。当字符串中没有小数时,评论中说无法正常工作的问题已在编辑前得到解决。 - Brent Sandstrom
如果数字非常小,例如0.00000001,num.toString()将返回类似于1e-7的内容,这段代码将无法正常工作。 - Orden
这对于一些“国际”号码也不起作用,其中数字可能写成 3.000,00 这样的形式。 - Hanna

10
function retr_dec(numStr) {
    var pieces = numStr.split(".");
    return pieces[1].length;
}

1
甚至更简单:numStr.split(".")[1].length; - Saša
1
值得指出的是,如果您的数字不是字符串,则此方法不起作用。为了使其起作用,请使用以下代码:var pieces = numStr.toString().split("."); - Claire
1
如果没有小数点,例如:123,则此情况将抛出错误。 - lobati

5

鉴于目前没有基于正则表达式的解答:

/\d*$/.exec(strNum)[0].length

请注意,这在整数情况下“失败”,但根据问题规格,它们永远不会发生。


5
我感谢您的评论和细致,但问题明确说明,“知道它们至少有1个小数位”。如果您因为这个原因对我的正确答案进行了反对投票,请重新考虑您的投票。 - Phrogz

3
您可以通过以下方式获取您数字的小数部分长度:
var value = 192.123123;
stringValue = value.toString();
length = stringValue.split('.')[1].length;

它将数字转化为字符串,将字符串在小数点处分成两部分,返回通过分割操作返回的数组的第二个元素的长度,并将其存储在'length'变量中。


OP 表示这些数字已经是字符串了。你的回答并没有提供任何新的东西,这已经被 Jack 和 Daniel Bidulock 建议过了。 - Mike Scotty
这绝对是回答 OP 问题最直接的方法。OP 没有要求考虑其他符号表示法(八进制?十六进制?)。 - PEWColina
请注意小数点前数字的科学表示法。当数字长度为20及以上时,它将启用。 - Jens Alenius

2
尝试使用String.prototype.match()RegExp /\..*/,返回匹配字符串.length的值减去-1

function retr_decs(args) {
  return /\./.test(args) && args.match(/\..*/)[0].length - 1 || "no decimal found"
}

console.log(
  retr_decs("23.456") // 3
  , retr_decs("9.450") // 3
  , retr_decs("123.01") // 2
  , retr_decs("123") // "no decimal found"
)


1
FYI,这不包括尾随的0。retr_decs("9.00") // "未找到小数" - Gaʀʀʏ
这很奇怪。昨天我测试时没有计算尾随零。我验证了你的jsfiddle和本地,发现函数正在处理它们。奇怪。你有我的赞成。 - Gaʀʀʏ

2

我需要处理非常小的数字,因此我创建了一个版本,可以处理类似1e-7这样的数字。

Number.prototype.getPrecision = function() {
  var v = this.valueOf();
  if (Math.floor(v) === v) return 0;
  var str = this.toString();
  var ep = str.split("e-");
  if (ep.length > 1) {
    var np = Number(ep[0]);
    return np.getPrecision() + Number(ep[1]);
  }
  var dp = str.split(".");
  if (dp.length > 1) {
    return dp[1].length;
  }
  return 0;
}
document.write("NaN => " + Number("NaN").getPrecision() + "<br>");
document.write("void => " + Number("").getPrecision() + "<br>");
document.write("12.1234 => " + Number("12.1234").getPrecision() + "<br>");
document.write("1212 => " + Number("1212").getPrecision() + "<br>");
document.write("0.0000001 => " + Number("0.0000001").getPrecision() + "<br>");
document.write("1.12e-23 => " + Number("1.12e-23").getPrecision() + "<br>");
document.write("1.12e8 => " + Number("1.12e8").getPrecision() + "<br>");


1
这是两个其他帖子的混合体,但对我有效。其他人没有处理我的代码中的外部情况。不过,我已经删除了科学小数点计数器。在大学里我会喜欢它!
numberOfDecimalPlaces: function (number) {
    var match = ('' + number).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
    if (!match || match[0] == 0) {
        return 0;
    }
     return match[0].length;
}

如果您删除科学小数点计数器,可以简化您的正则表达式: /(?:.(\d+))?$/此外,您应该使用match[0]而不是match[1]。 - Fl4v

1
这是目前被接受的答案的微小修改,它在Number原型中添加了内容,因此允许所有数字变量执行此方法:
if (!Number.prototype.getDecimals) {
    Number.prototype.getDecimals = function() {
        var num = this,
            match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
        if (!match)
            return 0;
        return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
    }
}

它可以这样使用:

// Get a number's decimals.
var number = 1.235256;
console.debug(number + " has " + number.getDecimals() + " decimal places.");

// Get a number string's decimals.
var number = "634.2384023";
console.debug(number + " has " + parseFloat(number).getDecimals() + " decimal places.");

利用我们现有的代码,第二种情况也可以轻松地添加到 String 原型中,如下所示:

if (!String.prototype.getDecimals) {
    String.prototype.getDecimals = function() {
        return parseFloat(this).getDecimals();
    }
}

使用方法如下:
console.debug("45.2342".getDecimals());

0
function decimalPlaces(n) {
  if (n === NaN || n === Infinity)
    return 0;
  n = ('' + n).split('.');
  if (n.length == 1) {
    if (Boolean(n[0].match(/e/g)))
      return ~~(n[0].split('e-'))[1];
    return 0;

  }
  n = n[1].split('e-');
  return n[0].length + ~~n[1];

}

这将处理每个条件,无论是科学的还是非科学的。 - dke
将其转换为字符串并检查科学计数法不是这个问题的重点(该问题已经存在近6年时间)。 - piksel bitworks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接