JavaScript处理数字分位符号

昨天做一个页面有一个需求,需要把服务器取过来的数字(也有可能是数字字符串),将小数点前的数字每隔三位添加一个逗号(前面数是一个四位数的值)。比如取到的值是123456,要将其转换成123,456。搜索了一下,这叫数字分位符号。

为了方便阅读小数点前后的数字可以被分组,由于国际上语言里最常见的数字读法是千位分位,写法的分组也是在千位数上。 如果当地习俗是用句点作小数点,千位的分号一般是逗号或空格。如果习俗里小数点是逗号,千位分号一般是句点或空格。由于可能产生歧义,国际标准建议、国际度量衡局更是要求用空格而不要用逗号或点。

不同国家有不同的标准要求,我们看看我国的标准:

为便于阅读,四位以上的整数或小数,可采用以下两种方式分节:

  • 千分撇: 整数部分每三位一组,以,分节。小数部分不分节。四位以内的整数可以不分节。如:624,00092,300,000、 19,351,235.235767,1256
  • 千分空: 从小数点起,向左和向右每三位数字一组,组间空四分之一个汉字,即二分之一个阿拉伯数字的位置。四位以内的整数可以不加千分空。如:55 235346、 23 98 235、 358.238、 368

可见,中国正式场合的数字用法并非是以万位数为一组来分节的。诸如123,4567.89的表示法是错误的。

JavaScript如何处理数字分位符

在这样的一个实际需求当中,取到的值不外呼是两种,其一它就是一个数字类型(整型123456或者浮点型12345.09),其二是一个数字字符串,比如"123456"。那回到主题上,现在需要将这样的数字或字符串做处理。

  • 需要创建一个函数,比如addCommas(),并且给这个函数传递一个参数val。需要注意的是,这个val值有可能是数字类型,也有可能是字符类型。
  • 不管获取的val是什么类型,首先通过toString()方法,将其转换成字符串
  • 由于取到的val值有可能是一个浮点数,而我们是需要给小数点前面的整数部分添加分位符号,;在JavaScript中可以通过split(".")将这个val转换成一个数组aIntNmu。如果val值是一个整数,那么得到的数组只有一个值,如果val是一个浮点数,那么将会以小数点为分隔点,数整会有两个元素值。我们要处理的将是aIntNum[0]
  • 通过正则replace()主法给aIntNum[0]做替换,这里需要一个正则规则,比如/(\d+)(\d{3})/。正则这部分,对于我这样的菜鸟而言还是很吃力的,不过这有个在线工具,可以检测并解释其函数。
  • 如果你想让JavaScript处理数字千分位更符合国家的标准,那么在做数据替换时,还需要做一个条件判断。比如说,只有当aIntNum[0].length大于或等于5的时候才添加分位符。
  • 返回处理的数字

上面方法是通过数组来处理的,其实还可以直接通过字符串处理来解决。比如通过indexOf(".")对数字分隔,再配合for循环、charAt()substr()等方法给数字添加分位符。接下来,我们一起看看代码具体如何写。

数组方案

根据前面的介绍的,先用数组的方式来做:

function addCommas(val) {
    //根据`.`作为分隔,将val值转换成一个数组
    var aIntNum = val.toString().split('.');
    // 整数部分
    var iIntPart = aIntNum[0];
    // 小数部分(传的值有小数情况之下)
    var iFlootPart = aIntNum.length > 1 ? '.' + aIntNum[1] : '';
    var rgx = /(\d+)(\d{3})/;
    // 如果整数部分位数大于或等于5
    if (iIntPart.length >= 5) {
        // 根据正则要求,将整数部分用逗号每三位分隔
        while (rgx.test(iIntPart)) {
            iIntPart = iIntPart.replace(rgx, '$1' + ',' + '$2');
        }
    }

    return iIntPart + iFlootPart;
}

上面的方法生不生效,难证一下就知道了:

addCommas(1234); // =>"1234"
addCommas(12345);// =>"12,345"
addCommas(123456);//=>"123,456"
addCommas(123456.4321);//=>"123,456.4321"
addCommas(123456.54321);//=>"123,456.54321"
addCommas(123456.654321);//=>"123,456.654321"

上面的方法只能小数点前面的数做了处理,如果需要对小数点后面的也做相应的处理,就需要做一下处理:

function addCommas(val) {
    //根据`.`作为分隔,将val值转换成一个数组
    var aIntNum = val.toString().split('.');
    // 整数部分
    var iIntPart = aIntNum[0];
    // 小数部分(传的值有小数情况之下)
    var iFlootPart = aIntNum.length > 1 ? '.' + aIntNum[1] : '';
    var rgx = /(\d+)(\d{3})/;
    // 如果整数部分位数大于或等于5
    if (iIntPart.length >= 5) {
        // 根据正则要求,将整数部分用逗号每三位分隔
        while (rgx.test(iIntPart)) {
            iIntPart = iIntPart.replace(rgx, '$1' + ',' + '$2');
        }
    }
    // 如果小数部分位数大于或等于5
    if (iFlootPart && iFlootPart.length >= 5) {
        // 根据正则要求,将小数部分用每三位分隔按空格号分开
        while (rgx.test(iFlootPart)) {
            iFlootPart = iFlootPart.replace(/(\d{3})/g, '$1 ');
        }
    }
    // 将整数部分和小数组部分合并在一起,并返回
    return iIntPart + iFlootPart;
}

调试器里继续跑一下测试代码:

addCommas(1234);//=>"1234"
addCommas(12345);//=>"12,345"
addCommas(123456);//=>"123,456"
addCommas(123456.4321);//=>"123,456.432 1"
addCommas(123456.54321);//=>"123,456.543 21"
addCommas(123456.654321);//=>"123,456.654 321 "

效果是有,但感觉怪怪的。

上面的代码可以精简一下,变成这样:

function addCommas(val) {
    var aIntNum = val.toString().split('.');
    if (aIntNum[0].length >= 5) {
        aIntNum[0] = aIntNum[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,');
    }
    if (aIntNum[1] && aIntNum[1].length >= 5) {
        aIntNum[1] = aIntNum[1].replace(/(\d{3})/g, '$1 ');
    }
    return aIntNum.join('.');
}

最后得到的效果就是一样。

将上面代码中的正则条件换换,也一样可以达到相同的效果:

function addCommas(val) {
    var aIntNum = val.toString().split(".");
    if (aIntNum[0].length >= 5) {
        aIntNum[0] = aIntNum[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }
    if (aIntNum[1] && aIntNum[1] >= 5) {
        aIntNum[1] = aIntNum[1] ? aIntNum[1].replace(/\B(?=(\d{3})+(?!\d))/g, " ") : " ";
    }
    return aIntNum.join(".");
}

字符串方案

前面也说了,除了将传参转换成数组去处理之外,还可以直接对传参进行字符串的操作。下面收集了几种方法,虽然达到需求,但还是略有不同之处。比如小数部分用的不是空格分开,而是使用逗号分开。另外一点,就是没找到如何超过四位数才进行分隔处理。希望有高手能指点其中不足之处。

方法1

function addCommas(val) {
    while (/(\d+)(\d{3})/.test(val.toString())) {
        val = val.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
    }
    return val;
}

方法2

function addCommas(val) {
    var sIntNum = val.toString(),
        bIndex = sIntNum.indexOf('.');
    return sIntNum.replace(/\d(?=(?:\d{3})+(?:\.|$))/g, function($0, i) {
        return bIndex < 0 || i < bIndex ? ($0 + ',') : $0;
    });
}

方法3

function addCommas(val) {
    return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

方法4

function addCommas(val) {
    return (val + "").replace(/\b(\d+)((\.\d+)*)\b/g, function(a, b, c) {
        return (b.charAt(0) > 0 && !(c || ".").lastIndexOf(".") ? b.replace(/(\d)(?=(\d{3})+$)/g, "$1,") : b) + c;
    });
}

总结

上面整理了使用数组或者直接操作字符串的几种方法,将一个数字或数字字符串,按照千分位的方式给其添加对应的分隔符,比如,或空格。虽然达到了一定的需求,但感觉里面的还存在一定的问题,只是没有找到问题所在。希望大婶们指点其中不对之处,如果您有更好的方案,欢迎在下面的评论中与我们一起分享。

扩展阅读

原文链接:https://www.w3cplus.com/javascript/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript.html

发表评论

登录后才能评论