Регулярное выражение для форматирования чисел в JavaScript - PullRequest
39 голосов
/ 12 февраля 2010

Мне нужно отобразить отформатированное число на веб-странице, используя JavaScript. Я хочу отформатировать его так, чтобы в нужных местах были запятые. Как бы я сделал это с помощью регулярного выражения? Я дошел до чего-то вроде этого:

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

... а потом понял, что это будет сложнее, чем я думаю (а приведенное выше выражение даже близко не к тому, что мне нужно). Я провел некоторые поиски, и мне трудно найти что-то подходящее для этого.

В основном, я хочу эти результаты:

  • 45 становится 45
  • 3856 становится 3856
  • 398868483992 становится 398 868 483 992

... вы поняли идею.

Ответы [ 11 ]

108 голосов
/ 12 февраля 2010

Это может быть сделано в одном регулярном выражении, итерация не требуется. Если ваш браузер поддерживает ECMAScript 2018, вы можете просто использовать lookaround и просто вставлять запятые в нужных местах:

Найдите (?<=\d)(?=(\d\d\d)+(?!\d)) и замените все на ,

В старых версиях JavaScript не поддерживает просмотр задним числом, поэтому он не работает. К счастью, нам нужно только немного измениться:

Найдите (\d)(?=(\d\d\d)+(?!\d)) и замените все на \1,

Итак, в JavaScript это будет выглядеть так:

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

Объяснение: Утвердить, что начиная с текущей позиции в строке и далее можно сопоставлять цифры, кратные трем, и что от текущей позиции остается цифра.

Это также будет работать с десятичными знаками (123456.78), если не слишком много цифр «справа от точки» (в противном случае вы получите 123 456 789 012).

Вы также можете определить его в прототипе Number следующим образом:

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

И затем использовать это так:

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

Кредит: Джеффри Фридл, Освоение регулярных выражений, 3-е. издание , стр. 66-67

16 голосов
/ 30 мая 2011

Форматирование числа может быть элегантно обработано одной строкой кода.

Этот код расширяет объект Number; примеры использования приведены ниже.

Код:

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

Как это работает

Регулярное выражение использует упреждающий поиск, чтобы найти позиции в строке, где единственное, что справа от нее, это одна или несколько группировок из трех чисел, пока не встретится ни десятичное число, ни конец строки. .split() используется для разбиения строки в этих точках на элементы массива, а затем .join() объединяет эти элементы обратно в строку, разделенные запятыми.

Концепция нахождения позиций внутри строки, а не совпадение с реальными символами, важна для разделения строки без удаления каких-либо символов.

Примеры использования:

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

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

Конечно, код может быть легко расширен или изменен в соответствии с региональными соображениями. Например, вот новая версия кода, которая автоматически определяет настройки языка и заменяет запятые и точки.

Версия с учетом локали:

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( "." );
    }
};

Если это действительно не нужно, я предпочитаю простоту первой версии.

3 голосов
/ 12 февраля 2010

// Возможно, вы захотите учесть десятичные дроби

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;

n.commas () = возвращаемое значение: (строка) 10 000 000 000.34

2 голосов
/ 12 февраля 2010

Если вы действительно хотите регулярное выражение, вы можете использовать два в цикле while:

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

И если вы хотите быть модным, вы можете также отформатировать числа с десятичными точками:

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

Edit:

Вы также можете сделать это с 2 регулярными выражениями без цикла, разбиений, объединений и т. Д .:

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

Первое регулярное выражение ставит запятую после первых 1 или 2 цифр, если оставшееся количество цифр делится на три. Второе регулярное выражение ставит запятую после каждой оставшейся группы из 3 цифр.

Они не будут работать с десятичными числами, но они отлично работают для положительных и отрицательных целых чисел.

Тестовый вывод:

45
3,856
398,868,483,992

635
12,358,717,859,918,856
-1,388,488,184
1 голос
/ 17 апреля 2013

underscore.string имеет хорошая реализация .

Я немного изменил его, чтобы принимать числовые строки.

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;
},
1 голос
/ 12 февраля 2010

Кто-то упомянул, что смотреть назад невозможно в Javascript RegExp. Вот отличная страница, которая объясняет, как использовать lookaround (lookahead и lookbehind).

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

0 голосов
/ 15 апреля 2014

Brandon

Я не видел слишком много ответов, работающих с регулярным выражением с десятичной точки назад, поэтому я подумал, что могу вмешаться.

Я задавался вопросом, есть ли какая-нибудь изящная выгода переписать регулярное выражение для сканирования назад ...

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 << </strong>

Это касается любого десятичного знака.

0 голосов
/ 12 февраля 2010

Итерации не нужны

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]));
}

Результаты

1
1

45
45

2856
2,856

398868483992
398,868,483,992
0 голосов
/ 12 февраля 2010

Сначала переверните массив символов, затем добавляйте запятые после каждого третьего числа, если только оно не находится перед концом строки или перед знаком -. Затем снова переверните массив символов и снова сделайте его строкой.

function add_commas(numStr){
    return numStr.split('').reverse().join('').replace(/(\d{3})(?=[^$|^-])/g, "$1,").split('').reverse().join('');
}
0 голосов
/ 12 февраля 2010

Я думаю, вам обязательно нужно сделать несколько проходов, чтобы добиться этого с помощью регулярных выражений. Попробуйте следующее:

  1. Запустите регулярное выражение для одной цифры, а затем 3 цифры.
  2. Если это регулярное выражение совпадает, замените его первой цифрой, затем запятой, а затем следующими 3 цифрами.
  3. Повторяйте, пока (1) не найдет совпадений.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...