千分位分隔數字並自定義保留小數位數

LFE發表於2018-02-01

功能:可實現不同符號分隔數字,可自定義分隔後數字保留的小數位數。

實現思路

    使用正則,用數字中的小數點做匹配尾部參考,來匹配某個數字後面的一個或多個連續3位數字,如果匹配到把該數字替換成自身加分隔符,如下:

  • 示例

1、 分隔數字:123456.1

解釋:3和.之間有一個連續3位數字(456),那麼給3後面新增一個分隔符得到結果:123,456.1。

2、分隔數字:1234567.1

解釋:1和.之間有兩個連續3位數字(234和567),那麼給1後面新增一個分隔符,然後數字4後面也存在一個連續三位數字(567),那麼也給4後面新增一個分隔符,最終得到結果1,234,567.1

匹配的正規表示式
/(\d)(?=(\d{3})+\.)/g;

這裡最難理解的就是(?=(\d{3})+\.),且看語法:
x(?=y):正向肯定查詢,匹配後面帶有y的x專案

那麼在這裡意思是:查詢一個和“.”之間帶有一個或多個連續3位數字的數字(x)
複製程式碼
最終實現
/**
 *num 要分隔的數字(必填)
 *n 保留的小數位數(可選)
 *symbol 分隔數字使用的符號(可選,預設為",")
 */ 
function splitNum(num,n,symbol) {
    if(!num)throw new Error('splitNum需要傳入一個待轉換的資料');
    if(typeof num!=='number')throw new TypeError('num引數應該是一個number型別');
    if(n<0)throw new Error('引數n不應該小於0');
    var hasDot=parseInt(num)!=num;//這裡檢測num是否為小數,true表示小數
    var m=(n!=undefined&&n!=null)?n:1;
    num=m==0?num.toFixed(m)+'.':hasDot?(n?num.toFixed(n):num):num.toFixed(m);
    symbol=symbol||',';
    num=num.toString().replace(/(\d)(?=(\d{3})+\.)/g,function(match, p1,p2) {
        return p1 + symbol;
    });
    if(n==0||(!hasDot&&!n)){//如果n為0或者傳入的num是整數並且沒有指定整數的保留位數,則去掉前面操作中的小數位
        num=num.substring(0,num.indexOf('.'));
    }
    return num;
}
複製程式碼

難點解惑

  • 1、也許有人會問,這裡是用“.”號做參考進行匹配的,如果傳進來的數字是一個整數呢,不就沒“.”號了嗎,所以在方法內部定義了m變數使其在操作過程中總能有個“.”號。

  • 2、num=m==0?num.toFixed(m)+'.':hasDot?(n?num.toFixed(n):num):num.toFixed(m);

num=m==0?num.toFixed(m)+'.':hasDot?(n?num.toFixed(n):num):num.toFixed(m);

作用:這裡的操作保證的是小數傳n、小數不傳n、整數傳n、整數不傳n四種情況都能正確返回小數位數
詳解:
1、如果m為零(傳入n=0)則直接經toFixed操作後再後面補“.”
2、如果m不為0,
    a、如果傳入數為小數
        a'、如果傳了n表示要保留小數,那麼需要num.toFixed(n)
        b'、如果沒傳n表示不需要對小數進行操作,直接返回原num
    b、如果傳入數為整數
        a'、直接對num進行toFixed(m)操作
複製程式碼

說明:該方法只適用於常用數字的操作,當數字超過一定位數時產生的精度問題這裡暫不做處理

自己寫的方法,如果有什麼不足之處歡迎指出交流,這裡的replace方法可參考我的另一篇文章

補充1:更簡單的原生方法

下面有老哥評論到:number型別可呼叫toLocalString()方法把他轉成本地語言環境格式顯示,經測試是可行的,但不需要攜帶引數,因為這些引數還是具有一定相容性問題的,直接可以像下面使用,具體參見MDN

var number=1234567891.23;
console.log(number.toLocaleString());//1,234,567,891.23
複製程式碼

相關文章