简体   繁体   English

JavaScript 中用于格式化数字的正则表达式

[英]Regular Expression for formatting numbers in JavaScript

I need to display a formatted number on a web page using JavaScript.我需要使用 JavaScript 在网页上显示一个格式化的数字。 I want to format it so that there are commas in the right places.我想格式化它,以便在正确的位置有逗号。 How would I do this with a regular expression?我将如何用正则表达式做到这一点? I've gotten as far as something like this:我已经得到了这样的东西:

myString = myString.replace(/^(\d{3})*$/g, "${1},");

...and then realized this would be more complex than I think (and the regex above is not even close to what I need). ...然后意识到这会比我想象的更复杂(上面的正则表达式甚至不接近我需要的)。 I've done some searching and I'm having a hard time finding something that works for this.我已经做了一些搜索,我很难找到适合这个的东西。

Basically, I want these results:基本上,我想要这些结果:

  • 45 becomes 45 45 变成 45
  • 3856 becomes 3,856 3856 变成 3,856
  • 398868483992 becomes 398,868,483,992 398868483992 变成 398,868,483,992

...you get the idea. ……你懂的。

This can be done in a single regex, no iteration required.这可以在单个正则表达式中完成,不需要迭代。 If your browser supports ECMAScript 2018, you could simply use lookaround and just insert commas at the right places:如果您的浏览器支持 ECMAScript 2018,您可以简单地使用环视并在正确的位置插入逗号:

Search for (?<=\\d)(?=(\\d\\d\\d)+(?!\\d)) and replace all with ,搜索(?<=\\d)(?=(\\d\\d\\d)+(?!\\d))并将所有内容替换为,

In older versions, JavaScript doesn't support lookbehind, so that doesn't work.在旧版本中,JavaScript 不支持后视,因此不起作用。 Fortunately, we only need to change a little bit:幸运的是,我们只需要稍微改变一下:

Search for (\\d)(?=(\\d\\d\\d)+(?!\\d)) and replace all with \\1,搜索(\\d)(?=(\\d\\d\\d)+(?!\\d))并将所有替换为\\1,

So, in JavaScript, that would look like:所以,在 JavaScript 中,这看起来像:

result = subject.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");

Explanation: Assert that from the current position in the string onwards, it is possible to match digits in multiples of three, and that there is a digit left of the current position.说明:断言从字符串中的当前位置开始,可以匹配三的倍数的数字,并且当前位置还剩一个数字。

This will also work with decimals (123456.78) as long as there aren't too many digits "to the right of the dot" (otherwise you get 123,456.789,012).只要“点的右边”没有太多数字(否则你会得到 123,456.789,012),这也适用于小数 (123456.78)。

You can also define it in a Number prototype, as follows:您还可以在 Number 原型中定义它,如下所示:

Number.prototype.format = function(){
   return this.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
};

And then using it like this:然后像这样使用它:

var num = 1234;
alert(num.format());

Credit: Jeffrey Friedl, Mastering Regular Expressions, 3rd.图片来源:Jeffrey Friedl,掌握正则表达式,第 3 期。 edition , p.,第66-67 66-67

Formatting a number can be handled elegantly with one line of code.可以用一行代码优雅地处理数字格式。

This code extends the Number object;此代码扩展了 Number 对象; usage examples are included below.下面包括使用示例。

Code:代码:

Number.prototype.format = function () {
    return this.toString().split( /(?=(?:\d{3})+(?:\.|$))/g ).join( "," );
};

How it works怎么运行的

The regular expression uses a look-ahead to find positions within the string where the only thing to the right of it is one or more groupings of three numbers, until either a decimal or the end of string is encountered.正则表达式使用前瞻来查找字符串中的位置,它的右侧唯一的是一个或多个三个数字的分组,直到遇到小数或字符串结尾。 The .split() is used to break the string at those points into array elements, and then the .join() merges those elements back into a string, separated by commas. .split()用于将这些点处的字符串分解为数组元素,然后.join()将这些元素合并回一个字符串,以逗号分隔。

The concept of finding positions within the string, rather than matching actual characters, is important in order to split the string without removing any characters.在字符串中查找位置而不是匹配实际字符的概念对于拆分字符串而不删除任何字符很重要。

Usage examples:用法示例:

var n = 9817236578964235;
alert( n.format() );    // Displays "9,817,236,578,964,235"

n = 87345.87;
alert( n.format() );    // Displays "87,345.87"

Of course, the code can easily be extended or changed to handle locale considerations.当然,可以很容易地扩展或更改代码以处理区域设置问题。 For example, here is a new version of the code that automatically detects the locale settings and swaps the use of commas and periods.例如,这是一个新版本的代码,它自动检测区域设置并交换逗号和句点的使用。

Locale-aware version:本地化版本:

Number.prototype.format = function () {

    if ((1.1).toLocaleString().indexOf(".") >= 0) {
        return this.toString().split( /(?=(?:\d{3})+(?:\.|$))/g ).join( "," );
    }
    else {
        return this.toString().split( /(?=(?:\d{3})+(?:,|$))/g ).join( "." );
    }
};

Unless it's really necessary, I prefer the simplicity of the first version though.除非真的有必要,否则我更喜欢第一个版本的简单性。

// You might want to take decimals into account // 您可能需要考虑小数

Number.prototype.commas= function(){
 var s= '', temp, 
 num= this.toString().split('.'), n=num[0];
 while(n.length> 3){
  temp= n.substring(n.length-3);
  s= ','+temp+s;
  n= n.slice(0, -3);
 }
 if(n) s= n+s;
 if(num[1]) s+='.'+num[1];
 return s;
}

var n= 10000000000.34; var n = 10000000000.34;

n.commas() = returned value: (String) 10,000,000,000.34 n.commas() = 返回值:(字符串)10,000,000,000.34

With the caveat that Intl.NumberFormat and Number.toLocaleString() are now there for this purpose in JavaScript:需要注意的是Intl.NumberFormatNumber.toLocaleString()现在在 JavaScript 中用于此目的:

The other answers using regular expressions all break down for decimal numbers (although the authors seem to not know this because they have only tested with 1 or 2 decimal places).使用正则表达式的其他答案都分解为十进制数(尽管作者似乎不知道这一点,因为他们只测试了 1 或 2 个小数位)。 This is because without lookbehind, JS regular expressions have no way to know whether you are working with the block of digits before or after the decimal point.这是因为没有lookbehind,JS正则表达式无法知道您是在处理小数点之前还是之后的数字块。 That leaves two ways to address this with JS regular expressions:这留下了两种使用 JS 正则表达式解决这个问题的方法:

  1. Know whether there is a decimal point in the number, and use different regular expressions depending on that:知道数字中是否有小数点,并根据它使用不同的正则表达式:

    • /(\\d)(?=(\\d{3})+$)/g for integers /(\\d)(?=(\\d{3})+$)/g对于整数
    • /(\\d)(?=(\\d{3})+\\.)/g for decimals /(\\d)(?=(\\d{3})+\\.)/g表示小数
  2. Use two regular expressions, one to match the decimal portion, and a second to do a replace on it.使用两个正则表达式,一个匹配小数部分,第二个对其进行替换。

 function format(num) { return num.toString().replace(/^[+-]?\\d+/, function(int) { return int.replace(/(\\d)(?=(\\d{3})+$)/g, '$1,'); }); } console.log(format(332432432)) console.log(format(332432432.3432432)) console.log(format(-332432432)) console.log(format(1E6)) console.log(format(1E-6))

function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
var num=numberWithCommas(2000000); //any number
console.log(num);

enter code here

Try this试试这个

underscore.string has a nice implementation . underscore.string一个很好的实现

I've amended it slightly to accept numeric strings.我稍微修改了它以接受数字字符串。

 function numberFormat(number, dec, dsep, tsep) { if (isNaN(number) || number == null) return ''; number = parseFloat(number).toFixed(~~dec); tsep = typeof tsep == 'string' ? tsep : ','; var parts = number.split('.'), fnums = parts[0], decimals = parts[1] ? (dsep || '.') + parts[1] : ''; return fnums.replace(/(\\d)(?=(?:\\d{3})+$)/g, '$1' + tsep) + decimals; } console.log(numberFormat(123456789)) console.log(numberFormat(123456789.123456789)) console.log(numberFormat(-123456789)) console.log(numberFormat(1E6)) console.log(numberFormat(1E-6)) console.log('---') console.log(numberFormat(123456789, 6, ',', '_')) console.log(numberFormat(123456789.123456789, 6, ',', '_')) console.log(numberFormat(-123456789, 6, ',', '_')) console.log(numberFormat(1E6, 6, ',', '_')) console.log(numberFormat(1E-6, 6, ',', '_'))

Try something like this:尝试这样的事情:

function add_commas(numStr)
{
    numStr += '';
    var x = numStr.split('.');
    var x1 = x[0];
    var x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}

If you really want a regex, you can use two in a while loop:如果你真的想要一个正则表达式,你可以在一个 while 循环中使用两个:

while(num.match(/\d{4}/)) {
    num = num.replace(/(\d{3})(,\d|$)/, ',$1$2');
}

And if you want to be fancy, you can format numbers with decimal points too:如果你想花哨,你也可以用小数点格式化数字:

while(num.match(/\d{4}(\,|\.)/)) {
    num = num.replace(/(\d{3})(,\d|$|\.)/, ',$1$2');
}

Edit:编辑:

You can also do this with 2 regular expressions and no loop, splits, joins, etc:您还可以使用 2 个正则表达式执行此操作,并且没有循环、拆分、连接等:

num = num.replace(/(\d{1,2}?)((\d{3})+)$/, "$1,$2");
num = num.replace(/(\d{3})(?=\d)/g, "$1,");

The first regex puts a comma after the first 1 or 2 digits if the remaining number of digits is divisible by three.如果剩余的位数可以被 3 整除,则第一个正则表达式会在前 1 或 2 位数字后放置一个逗号。 The second regex places a comma after every remaining group of 3 digits.第二个正则表达式在剩余的每组 3 位数字后放置一个逗号。

These won't work with decimals, but they work great for positive and negative integers.这些不适用于小数,但它们适用于正整数和负整数。

Test output:测试输出:

45
3,856
398,868,483,992

635
12,358,717,859,918,856
-1,388,488,184

Someone mentioned that lookbehind isn't possible in Javascript RegExp.有人提到在 Javascript RegExp 中不可能进行后视。 Here is a great page that explains how to use lookaround (lookahead and lookbehind).这是一个很棒的页面,解释了如何使用环视(前瞻和后视)。

http://www.regular-expressions.info/lookaround.html http://www.regular-expressions.info/lookaround.html

One RegExp for integers and decimals:整数和小数的一个 RegExp:

// Formats number 1234.5678 into string "1 234.5678".
function formatNumber(number: number): string {
    return number.toString().replace(/(?<!(\.\d*|^.{0}))(?=(\d{3})+(?!\d))/g, ' ');
}

console.log(formatNumber(1234.5678)); // "1 234.5678"
console.log(formatNumber(123)); // "123"
console.log(formatNumber(123.45678)); // "123.45678"
console.log(formatNumber(123456789.11111111)); // "123 456 789.1111111"

I think you would necessarily have to do multiple passes to achieve this with regular expressions.我认为您必须进行多次传递才能使用正则表达式实现这一点。 Try the following:请尝试以下操作:

  1. Run a regex for one digit followed by 3 digits.运行一位数字后跟 3 位数字的正则表达式。
  2. If that regex matches, replace it with the first digit, then a comma, then the next 3 digits.如果该正则表达式匹配,则将其替换为第一位数字,然后是逗号,然后是接下来的 3 位数字。
  3. Repeat until (1) finds no matches.重复直到 (1) 找不到匹配项。

First reverse a character array, then add commas after every third number unless it's just before the end of the string or before a - sign.首先反转一个字符数组,然后在每三个数字后添加逗号,除非它就在字符串末尾或 - 符号之前。 Then reverse the character array again and make it a string again.然后再次反转字符数组并再次使其成为字符串。

function add_commas(numStr){
    return numStr.split('').reverse().join('').replace(/(\d{3})(?=[^$|^-])/g, "$1,").split('').reverse().join('');
}

Iteration isn't necessary迭代不是必需的

function formatNumber(n, separator) {
    separator = separator || ",";

    n = n.toString()
        .split("").reverse().join("")
        .replace(/(\d{3})/g, "$1" + separator)
        .split("").reverse().join("");

    // Strings that have a length that is a multiple of 3 will have a leading separator
    return n[0] == separator ? n.substr(1) : n;
}

var testCases = [1, 45, 2856, 398868483992];
for ( var i in testCases ) {
    if ( !ns.hasOwnProperty(i) ) { continue; }
    console.info(testCases[i]);   
    console.log(formatNumber(testCases[i]));
}

Results结果

1
1

45
45

2856
2,856

398868483992
398,868,483,992

Brandon,布兰登,

I didn't see too many answers working the regex from the decimal point back, so I thought I might chime in.我没有看到太多从小数点开始使用正则表达式的答案,所以我想我可能会插话。

I wondered if there is any elegant benefit to re-writing the regexp to scan from the back forward...我想知道重写正则表达式以从后向前扫描是否有任何优雅的好处......

function addCommas(inputText) {
    // pattern works from right to left
    var commaPattern = /(\d+)(\d{3})(\.\d*)*$/;
    var callback = function (match, p1, p2, p3) {
        return p1.replace(commaPattern, callback) + ',' + p2 + (p3 || '');
    };
    return inputText.replace(commaPattern, callback);
}

>> Fiddle Demo << >> 小提琴演示 <<

This accounts for any decimal place.这占任何小数位。

After so much searching, I generate a regex which accepts all formats经过这么多搜索,我生成了一个接受所有格式的正则表达式

(\\d+[-, ,(]{0,3}\\d+[-, ,(,)]{0,3}\\d+[-, ,(,)]{0,3}\\d+[)]{0,2}) (\\d+[-, ,(]{0,3}\\d+[-, ,(,)]{0,3}\\d+[-, ,(,)]{0,3}\\d+[)]{ 0,2})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM