Hướng dẫn format big numbers javascript - định dạng số lớn javascript

Chức năng phổ quát, nhanh, chính xác, đơn giản

  • Sử dụng regex (nhanh và chính xác)
  • Số hỗ trợ (float/integer)/chuỗi/nhiều số trong chuỗi
  • Thông minh tốt (không nhóm số thập phân - tương thích với các loại nhóm khác nhau)
  • Hỗ trợ tất cả các trình duyệt đặc biệt 'Safari' & 'IE' và nhiều trình duyệt cũ hơn
  • [Tùy chọn] Tôn trọng các chữ số không phải tiếng Anh (tiếng Ba Tư/Ả Rập) (+ trước khi sửa)Persian/Arabic) digits (+ Pre-fix)
TL; DR - Hàm phiên bản đầy đủ (Minified):

// num: Number/s (String/Number),
// sep: Thousands separator (String) - Default: ','
// dec: Decimal separator (String) - Default: '.' (Just one char)
// u: Universal support for languages characters (String - RegEx character set / class) - Example: '[\\d\\u0660-\\u0669\\u06f0-\\u06f9]' (English/Persian/Arabic), Default: '\\d' (English)

function formatNums(num,sep,dec,u){sep=sep||',';u=u||'\\d';if(typeof num!='string'){num=String(num);if(dec&&dec!='.')num=num.replace('.',dec);}return num.replace(RegExp('\\'+(dec||'.')+u+'+|'+u+'(?=(?:'+u+'{3})+(?!'+u+'))','g'),function(a){return a.length==1?a+sep:a})}

text='100000000 English or Persian/Arabic ۱۲۳۴۵۶۷۸۹/٠١٢٣٤٥٦٧٨٩ this is 123123123.123123123 with this -123123 and these 10 100 1000 123123/123123 (2000000) .33333 100.00 or any like 500000Kg';

console.log(formatNums(10000000.0012));
console.log(formatNums(10000000.0012,'.',',')); // German
console.log(formatNums(text,',','.','[\\d\\u0660-\\u0669\\u06f0-\\u06f9]')); // Respect Persian/Arabic digits

Tại sao không hài lòng với các câu trả lời khác?

  • Number.prototype.tolocalestring () / intl.numberformat (câu trả lời đúng)
    • Nếu không có tranh luận tốt, chúng ta không thể mong đợi kết quả tương tự. Ngoài ra với các tùy chọn đối số, chúng tôi vẫn không thể chắc chắn những gì có thể là kết quả vì nó sẽ sử dụng cài đặt cục bộ và hiệu ứng sửa đổi máy khách có thể có trên nó hoặc trình duyệt/thiết bị không hỗ trợ nó.we can't expect same result. Also with arguments options we still can't be sure what can be the result because it will use local settings and possible client modifications effect on it or the browser/device not support it.
    • > ~ 2016 Hỗ trợ trình duyệt và vẫn còn vào năm 2021, một số báo cáo rằng trong một số trường hợp như
      
      
      0 hoặc
      
      
      1 không quay lại như mong đợi.
      and still in 2021 some reports that in some cases like
      
      
      0 or
      
      
      1 do not return as expected.
    • 
      
      2 Làm việc với các số,
      
      
      3 làm việc với chuỗi/số; Chuỗi sẽ được/phải được phân tích cú pháp và cũng được làm tròn nếu cần thiết, vì vậy:
      • Nếu chúng ta đã có một chuỗi cục bộ với
        
        
        4, chúng ta phải thay thế số bằng tiếng Anh, thì hãy phân tích lại nó, sau đó sử dụng lại với các tùy chọn cục bộ. (Nếu nó trả lại những gì chúng ta mong đợi)
      • Nói chung trong khi phân tích cú pháp, chúng tôi không thể mong đợi không phải
        
        
        5 hoặc chi tiết trong
        
        
        6 hoặc tôn trọng
        
        
        7
    • Không thể tùy chỉnh các ký tự phân tách thập phân / nghìn nhiều hơn các tùy chọn ngôn ngữ, ngoại trừ với các sửa lỗi sau với thay thế () + regex một lần nữa. .
    • Hiệu suất chậm trong các vòng lặp
  • Cách Regex không tốt (cách nhanh nhất và một lớp lót)
    • 
      
      9 Nó cũng sẽ nhóm số thập phân.
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      0
    • // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      1 đã sử dụng Look-Ahind chưa hỗ trợ tốt. Vui lòng kiểm tra: https://caniuse.com/js-regexp-lookbehind https://developer.mozilla.org/en-us/docs/web/javascript của cấu trúc regex ban đầu (vì cách máy phân tích nên hoạt động như không đệm thô phía sau như một trình phân tích cú pháp) và thực sự nó có thể làm cho hiệu suất thấp nghiêm trọng (trong trường hợp này là ~ 30%). Tôi nghĩ rằng nó được đẩy vào bên trong thời gian theo yêu cầu.look-behind that not supported well yet. Please check:
      https://caniuse.com/js-regexp-lookbehind
      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#browser_compatibility
      Note: Generally lookbehind can be against of original RegEx structure (because of how the analyzer should work like do not buffer the raw behind as a parser) and actually it can make the performance seriously low (In this case ~30%). I think it pushed inside over the time by requests.
    • // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      2 Chỉ cần làm việc với số float và bỏ qua các số nguyên.
    • // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      3 (ý tưởng cũ của tôi) sử dụng 2 regex. Đầu tiên tìm thấy các phần số nguyên, phần thứ hai đặt dấu phân cách. Tại sao 2 chức năng, khi nó có thể được trộn lẫn?(My old idea) Using 2 RegEx. First one find the integer parts, second one put separator. Why 2 functions, when it can be mixed?
    • // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      4 (Ý tưởng tốt của @DJulien - Tôi đã bỏ phiếu) nhưng khi Regex là toàn cầu,
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      5, nó có thể phạm sai lầm ngay cả với một không gian cuối cùng. Ngoài ra, sử dụng các nhóm bắt giữ (ví dụ:
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      6) sẽ làm cho hiệu suất thấp, vì vậy nếu có thể, hãy sử dụng các nhóm không bắt giữ (ví dụ:
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      7) hoặc nếu một câu lệnh đã tồn tại trong chức năng của chúng tôi, hãy trộn nó. Trong trường hợp này, không sử dụng các nhóm bắt giữ cải thiện hiệu suất khoảng ~ 20% và trong trường hợp
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      8 so với
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      9, nhóm thứ hai nhanh hơn ~ 8%. Giới thiệu về các hiệu suất của Regex: Lưu ý: Chắc chắn các phương thức, trình duyệt, phần cứng, trạng thái hệ thống, trường hợp và thậm chí thay đổi trên ECMAscript sẽ ảnh hưởng đến kết quả của việc kiểm tra hiệu suất. Nhưng một số thay đổi về mặt logic nên có hiệu lực và tôi đã sử dụng cái này như là ví dụ trực quan.
      Also using capturing groups (Example:
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      6) will make the performance low so if it possible, use non-capturing groups (Example:
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      7) or if an statement already exist in our function let's mix it.
      In this case, not using capturing groups improve performance about ~20% and in case of
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      8 vs
      // 1000000.2301
      parseFloat(num) // (Pre-fix) If the input is string
          .toLocaleString('en-US', {
              useGrouping: true // (Default is true, here is just for show)
          });
      // 1,000,000.23
      
      9, the second one is ~8% faster.
      About regex performances:
      Hướng dẫn format big numbers javascript - định dạng số lớn javascript
      Note: Sure different methods, browsers, hardware, system status, cases and even changes on ECMAScript will effect on result of checking performance. But some changes logically should effect result and i used this one just as visual example.
  • Sử dụng thư viện như Numeral.js rất nhiều chức năng không cần thiết cho một nhiệm vụ đơn giản.so much not necessary functions for a simple task.
  • Mã nặng / không chính xác các chức năng đã sử dụng
    // 1000000.2301
    new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
        numberingSystem: 'arab'
    }).format(num)
    // ١٬٠٠٠٬٠٠٠٫٢٣
    
    0 hoặc
    // 1000000.2301
    new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
        numberingSystem: 'arab'
    }).format(num)
    // ١٬٠٠٠٬٠٠٠٫٢٣
    
    1 hoặc
    // 1000000.2301
    new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
        numberingSystem: 'arab'
    }).format(num)
    // ١٬٠٠٠٬٠٠٠٫٢٣
    
    2 ...Not accurate functions that used
    // 1000000.2301
    new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
        numberingSystem: 'arab'
    }).format(num)
    // ١٬٠٠٠٬٠٠٠٫٢٣
    
    0 or
    // 1000000.2301
    new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
        numberingSystem: 'arab'
    }).format(num)
    // ١٬٠٠٠٬٠٠٠٫٢٣
    
    1 or
    // 1000000.2301
    new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
        numberingSystem: 'arab'
    }).format(num)
    // ١٬٠٠٠٬٠٠٠٫٢٣
    
    2 ...

Kết quả cuối cùng:

Không có gì tốt nhất trong tất cả và nó nên được chọn dựa trên nhu cầu. Ưu tiên sắp xếp của tôi;

  1. Khả năng tương thích
  2. Khả năng
  3. Tính phổ quát
  4. Dễ sử dụng
  5. Màn biểu diễn


2 (Tương thích - Tính phổ quát) [Hàm gốc]

  • Nếu bạn phải thay đổi chữ số và nhóm từ tiếng Anh sang ngôn ngữ khác
  • Nếu bạn không chắc chắn về ngôn ngữ khách hàng của mình
  • Nếu bạn không cần có kết quả mong đợi chính xác
  • Nếu bạn không quan tâm đến phiên bản Safari cũ hơn
// 1000000.2301
parseFloat(num) // (Pre-fix) If the input is string
    .toLocaleString('en-US', {
        useGrouping: true // (Default is true, here is just for show)
    });
// 1,000,000.23

Đọc thêm: https://www.w3schools.com/jsref/jsref_tolocalestring_number.asp

// 1000000.2301
new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
    numberingSystem: 'arab'
}).format(num)
// ١٬٠٠٠٬٠٠٠٫٢٣
4 (Khả năng - Tính phổ biến - Tương thích) [Hàm gốc]

Gần như


2 +

  • Khả năng tuyệt vời của việc hỗ trợ tiền tệ, đơn vị, v.v ... bất kỳ ngôn ngữ nào (trình duyệt hiện đại)(Modern browsers)
// 1000000.2301
new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
    numberingSystem: 'arab'
}).format(num)
// ١٬٠٠٠٬٠٠٠٫٢٣

Đọc thêm: https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/intl/numberformat/numberformat

Với nhiều tùy chọn của các chức năng gốc, chúng tôi vẫn không thể mong đợi:

  • Kết quả chính xác (+ không phân tích cú pháp đầu vào / không làm tròn / không chuyển đổi số lớn)
  • Chấp nhận các chữ số ngôn ngữ khác làm đầu vào
  • Tùy chỉnh phân tách
  • Tin tưởng hỗ trợ trình duyệt
  • Màn biểu diễn

Vì vậy, bạn có thể cần một chức năng như bất kỳ trong số này:

// 1000000.2301
new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
    numberingSystem: 'arab'
}).format(num)
// ١٬٠٠٠٬٠٠٠٫٢٣
6 (Khả năng tương thích - Dễ sử dụng)

Phiên bản đầy đủ (khả năng) (không nhanh hơn Tolocalestring) - Giải thích: (Not faster than toLocaleString) - Explain:

function formatNums(num, sep, dec, u) {
    // Setting defaults
    sep = sep || ','; // Seperator
    u = u || '\\d'; // Universal character set \d: 0-9 (English)
    // Mixing of Handeling numbers when the decimal character should be changed + Being sure the input is string
    if (typeof num != 'string') {
        num = String(num);
        if (dec && dec != '.') num = num.replace('.', dec); // Replacing sure decimal character with the custom
    }
    //
    return num.replace(RegExp('\\' + (dec || '.') + u + '+|' + u + '(?=(?:' + u + '{3})+(?!' + u + '))', 'g'),
        // The RegEx will be like /\.\d+|\d(?=(?:\d{3})+(?!\d))/g if not be customized 
        // RegEx explain:
        // 1) \.\d+  :  First try to get any part that started with a dot and followed by any much of English digits, one or more (For ignoring it later)
        // 2) |  :  Or
        // 3) \d  :  Get any 1 char digit
        // 3.1) (?=...)  :  That the next of that should be
        // 3.2) (?:\d{3})  :  3 length digits
        // 3.2.1) +  :  One or more of the group
        // 3.3) (?!\d)  :  ...till any place that there is no digits
        function(a) { // Any match can be the decimal part or the integer part so lets check it
            return a.length == 1 ? a + sep : a // If the match is one character, it is from the grouping part as item (3) in Regex explain so add the seperator next of it, if not, ignore it and return it back.
        })
}

function formatNums(num,sep,dec,u) {
    sep=sep||',';
    u=u||'\\d';
    if(typeof num!='string') {
        num=String(num);
        if( dec && dec!='.') num=num.replace('.',dec);
    }
    return num.replace(RegExp('\\'+(dec||'.')+u+'+|'+u+'(?=(?:'+u+'{3})+(?!'+u+'))','g'),function(a) {return a.length==1 ? a+sep : a})
}
console.log(formatNums(1000000.2301));
console.log(formatNums(100.2301));
console.log(formatNums(-2000.2301));
console.log(formatNums(123123123,' , '));
console.log(formatNums('0000.0000'));
console.log(formatNums('5000000.00'));
console.log(formatNums('5000000,00',' ',','));
console.log(formatNums(5000000.1234,' ',','));
console.log(formatNums('۱۲۳۴۵۶۷۸۹/۹۰۰۰',',','/','[\\d\\u0660-\\u0669\\u06f0-\\u06f9]'));

Chơi với các ví dụ ở đây: https://jsfiddle.net/papionbit/198xl3te/

Phiên bản ánh sáng (hiệu suất) (nhanh hơn 30% so với Tolocalestring) (~30% faster than toLocaleString)

function formatNums(num,sep) {
    sep=sep||',';
    return String(num).replace(/\.\d+|\d(?=(?:\d{3})+(?!\d))/g,
        function(a) {
            return a.length==1?a+sep:a
        }
    );
}
console.log(formatNums(1000000.2301));
console.log(formatNums(100.2301));
console.log(formatNums(-2000.2301));
console.log(formatNums(123123123,' '));

Kiểm tra Regex (không có chức năng cần thiết): https://regexr.com/66ott

// 1000000.2301
new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
    numberingSystem: 'arab'
}).format(num)
// ١٬٠٠٠٬٠٠٠٫٢٣
7 (Hiệu suất - Tương thích)

Chọn tốt nhất nếu đầu vào được chỉ định / được xác định trước. .

num=1000000;
str='123123.100';
console.log((num+'').replace(/\B(?=(?:\d{3})+\b)/g,','));
console.log(str.replace(/\B(?=(?:\d{3})+\b)/g,','));

+

Đối với khách hàng địa phương Ba Tư/Ả Rập:

Nếu khách hàng của bạn sử dụng số tiếng Ba Tư/tiếng Ả Rập cho đầu vào như thường lệ ở Iran, tôi nghĩ cách tốt nhất là thay vì giữ các ký tự gốc, hãy chuyển đổi chúng sang tiếng Anh trước khi bạn giải quyết, để bạn có thể tính toán nó.

// ۱۲۳۴۵۶۷۸۹۰
function toEnNum(n) { // Replacing Persian/Arabic numbers character with English
    n.replace(/[\u0660-\u0669\u06f0-\u06f9]/g, // RegEx unicode range Persian/Arabic numbers char
        function(c) {
            return c.charCodeAt(0) & 0xf; // Replace the char with real number by getting the binary index and breaking to lowest using 15
        }
    );
}
// 1234567890

Và vẫn cho họ thấy chúng là cái nhìn nguyên bản, có 2 cách:

  • CSS sử dụng phông chữ Ba Tư/Ả Rập với các chữ số cục bộ (lựa chọn của tôi) Using Persian/Arabic fonts with local digits (My choose)
  • Chuyển đổi kết quả trở lại với
    
    
    3 hoặc một chức năng như: https://stackoverflow.com/a/13787021/7514010

Chức năng trường học cũ của tôi trên bài đăng này: (~ 15% so với TolocalString) on this post: (~15% Faster than toLocalString)

// 10000000.0012
function formatNums(n, s) {
    return s = s || ",", String(n).
    replace(/(?:^|[^.\d])\d+/g, // First this RegEx take just integer parts
        function(n) {
            return n.replace(/\B(?=(?:\d{3})+\b)/g, s);
        })
}
// 10,000,000.0012