Как напечатать число с запятой в качестве разделителя разрядов в JavaScript

Я пытаюсь напечатать целое число в JavaScript с запятыми в качестве разделителей тысяч. Например, я хочу показать число 1234567 как "1,234,567". Как мне это сделать?

вот как я делаю это:

function numberWithCommas(x) {
    x = x.toString();
    var pattern = /(-?d+)(d{3})/;
    while (pattern.test(x))
        x = x.replace(pattern, ",");
    return x;
}

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

30 ответов


const numberWithCommas = (x) => {
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

Это все, что вам действительно нужно знать.

@Neils Bom спросил, как работает регулярное выражение. Мое объяснение довольно длинное. Он не будет вписываться в комментарии, и я не знаю, куда еще его поместить, поэтому я делаю это здесь. Если у кого-то есть другие предложения о том, куда его поместить, пожалуйста, дайте мне знать.

в regex использует 2 утверждения lookahead: положительное, чтобы искать любую точку в строке, которая имеет несколько 3 цифр в строке после нее, и отрицательное утверждение, чтобы убедиться, что точка имеет только ровно несколько 3 цифр. Выражение замены ставит запятую.

например, если вы передадите его "123456789.01", положительное утверждение будет соответствовать каждому пятну слева от 7 (так как" 789 "кратно 3 цифрам," 678 "кратно 3 цифрам," 567 " и т. д.). Этот отрицательное утверждение проверяет, что несколько из 3 цифр не имеют никаких цифр после него. "789" имеет период после него, поэтому он точно кратен 3 цифрам, поэтому запятая идет туда. "678 "кратно 3 цифрам, но после него есть" 9", поэтому эти 3 цифры являются частью группы из 4, и запятая туда не идет. Аналогично для "567". "456789" - это 6 цифр, что кратно 3, поэтому запятая идет до этого. "345678" кратно 3, но после него есть" 9", поэтому запятая туда не идет. И так далее. "\B " не позволяет регулярному выражению ставить запятую в начале строки.

@neu-rah упомянула, что эта функция добавляет запятые в нежелательных местах, если после десятичной точки больше 3 цифр. Если это проблема, вы можете использовать эту функцию:

const numberWithCommas = (x) => {
  var parts = x.toString().split(".");
  parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return parts.join(".");
}

Я удивлен, что никто не упомянул количество.прототип.методом tolocalestring. Он реализован в JavaScript 1.5 (который был представлен в 1999 году), поэтому он в основном поддерживается в основных браузерах.

var n = 34523453.345
n.toLocaleString()
"34,523,453.345"

Он также работает в узле.js по состоянию на v0.12 через включение Intl

Если вы хотите что-то другое, цифра.js может быть интересно.


var number = 1234567890; // Example number to be converted

Mind имейте в виду, что javascript имеет максимальное целое число стоимостью 9007199254740991


методом tolocalestring:

number.toLocaleString(); // "1,234,567,890"

// A more complex example: 
var number2 = 1234.56789; // floating point example
number2.toLocaleString(undefined, {maximumFractionDigits:2}) // "1,234.57"


NumberFormat (сафари не поддерживается):

var nf = new Intl.NumberFormat();
nf.format(number); // "1,234,567,890"

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


Я предлагаю использовать phpjs.org s number_format ()

function number_format(number, decimals, dec_point, thousands_sep) {
    // http://kevin.vanzonneveld.net
    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +     bugfix by: Michael White (http://getsprink.com)
    // +     bugfix by: Benjamin Lupton
    // +     bugfix by: Allan Jensen (http://www.winternet.no)
    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +     bugfix by: Howard Yeend
    // +    revised by: Luke Smith (http://lucassmith.name)
    // +     bugfix by: Diogo Resende
    // +     bugfix by: Rival
    // +      input by: Kheang Hok Chin (http://www.distantia.ca/)
    // +   improved by: davook
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Jay Klehr
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Amir Habibi (http://www.residence-mixte.com/)
    // +     bugfix by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Theriault
    // +   improved by: Drew Noakes
    // *     example 1: number_format(1234.56);
    // *     returns 1: '1,235'
    // *     example 2: number_format(1234.56, 2, ',', ' ');
    // *     returns 2: '1 234,56'
    // *     example 3: number_format(1234.5678, 2, '.', '');
    // *     returns 3: '1234.57'
    // *     example 4: number_format(67, 2, ',', '.');
    // *     returns 4: '67,00'
    // *     example 5: number_format(1000);
    // *     returns 5: '1,000'
    // *     example 6: number_format(67.311, 2);
    // *     returns 6: '67.31'
    // *     example 7: number_format(1000.55, 1);
    // *     returns 7: '1,000.6'
    // *     example 8: number_format(67000, 5, ',', '.');
    // *     returns 8: '67.000,00000'
    // *     example 9: number_format(0.9, 0);
    // *     returns 9: '1'
    // *    example 10: number_format('1.20', 2);
    // *    returns 10: '1.20'
    // *    example 11: number_format('1.20', 4);
    // *    returns 11: '1.2000'
    // *    example 12: number_format('1.2000', 3);
    // *    returns 12: '1.200'
    var n = !isFinite(+number) ? 0 : +number, 
        prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
        sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
        dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
        toFixedFix = function (n, prec) {
            // Fix for IE parseFloat(0.55).toFixed(0) = 0;
            var k = Math.pow(10, prec);
            return Math.round(n * k) / k;
        },
        s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.');
    if (s[0].length > 3) {
        s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
    }
    if ((s[1] || '').length < prec) {
        s[1] = s[1] || '';
        s[1] += new Array(prec - s[1].length + 1).join('0');
    }
    return s.join(dec);
}

обновление 02/13/14

люди сообщали, что это не работает, как ожидалось, поэтому я сделал JS Fiddle Это включает автоматические тесты.

обновление 26.11.2017

вот эта скрипка как фрагмент стека со слегка измененным выходом:

function number_format(number, decimals, dec_point, thousands_sep) {
    // http://kevin.vanzonneveld.net
    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +     bugfix by: Michael White (http://getsprink.com)
    // +     bugfix by: Benjamin Lupton
    // +     bugfix by: Allan Jensen (http://www.winternet.no)
    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +     bugfix by: Howard Yeend
    // +    revised by: Luke Smith (http://lucassmith.name)
    // +     bugfix by: Diogo Resende
    // +     bugfix by: Rival
    // +      input by: Kheang Hok Chin (http://www.distantia.ca/)
    // +   improved by: davook
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Jay Klehr
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Amir Habibi (http://www.residence-mixte.com/)
    // +     bugfix by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Theriault
    // +   improved by: Drew Noakes
    // *     example 1: number_format(1234.56);
    // *     returns 1: '1,235'
    // *     example 2: number_format(1234.56, 2, ',', ' ');
    // *     returns 2: '1 234,56'
    // *     example 3: number_format(1234.5678, 2, '.', '');
    // *     returns 3: '1234.57'
    // *     example 4: number_format(67, 2, ',', '.');
    // *     returns 4: '67,00'
    // *     example 5: number_format(1000);
    // *     returns 5: '1,000'
    // *     example 6: number_format(67.311, 2);
    // *     returns 6: '67.31'
    // *     example 7: number_format(1000.55, 1);
    // *     returns 7: '1,000.6'
    // *     example 8: number_format(67000, 5, ',', '.');
    // *     returns 8: '67.000,00000'
    // *     example 9: number_format(0.9, 0);
    // *     returns 9: '1'
    // *    example 10: number_format('1.20', 2);
    // *    returns 10: '1.20'
    // *    example 11: number_format('1.20', 4);
    // *    returns 11: '1.2000'
    // *    example 12: number_format('1.2000', 3);
    // *    returns 12: '1.200'
    var n = !isFinite(+number) ? 0 : +number, 
        prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
        sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
        dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
        toFixedFix = function (n, prec) {
            // Fix for IE parseFloat(0.55).toFixed(0) = 0;
            var k = Math.pow(10, prec);
            return Math.round(n * k) / k;
        },
        s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.');
    if (s[0].length > 3) {
        s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
    }
    if ((s[1] || '').length < prec) {
        s[1] = s[1] || '';
        s[1] += new Array(prec - s[1].length + 1).join('0');
    }
    return s.join(dec);
}

var exampleNumber = 1;
function test(expected, number, decimals, dec_point, thousands_sep)
{
    var actual = number_format(number, decimals, dec_point, thousands_sep);
    console.log(
        'Test case ' + exampleNumber + ': ' +
        '(decimals: ' + (typeof decimals === 'undefined' ? '(default)' : decimals) +
        ', dec_point: "' + (typeof dec_point === 'undefined' ? '(default)' : dec_point) + '"' +
        ', thousands_sep: "' + (typeof thousands_sep === 'undefined' ? '(default)' : thousands_sep) + '")'
    );
    console.log('  => ' + (actual === expected ? 'Passed' : 'FAILED') + ', got "' + actual + '", expected "' + expected + '".');
    exampleNumber++;
}

test('1,235',    1234.56);
test('1 234,56', 1234.56, 2, ',', ' ');
test('1234.57',  1234.5678, 2, '.', '');
test('67,00',    67, 2, ',', '.');
test('1,000',    1000);
test('67.31',    67.311, 2);
test('1,000.6',  1000.55, 1);
test('67.000,00000', 67000, 5, ',', '.');
test('1',        0.9, 0);
test('1.20',     '1.20', 2);
test('1.2000',   '1.20', 4);
test('1.200',    '1.2000', 3);
.as-console-wrapper {
  max-height: 100% !important;
}

Это вариант ответа @mikez302, но модифицированный для поддержки чисел с десятичными знаками (в обратной связи @neu-rah, что numberWithCommas(12345.6789) -> "12,345.6,789" вместо "12 345".6789"

function numberWithCommas(n) {
    var parts=n.toString().split(".");
    return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
}

function formatNumber (num) {
    return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, ",")
}

print(formatNumber(2665));      // 2,665
print(formatNumber(102665));    // 102,665
print(formatNumber(111102665)); // 111,102,665

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

первый фрагмент добавляет функцию, которая имитирует PHP ' s number_format() к прототипу количество. Если я форматирую число, я обычно хочу десятичные знаки, поэтому функция принимает количество десятичных знаков для отображения. Некоторые страны используют запятые в качестве десятичных и десятичных знаков в качестве разделителя тысяч, поэтому функция позволяет этим разделителям будьте готовы.

Number.prototype.numberFormat = function(decimals, dec_point, thousands_sep) {
    dec_point = typeof dec_point !== 'undefined' ? dec_point : '.';
    thousands_sep = typeof thousands_sep !== 'undefined' ? thousands_sep : ',';

    var parts = this.toFixed(decimals).split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousands_sep);

    return parts.join(dec_point);
}

вы бы использовали это следующим образом:

var foo = 5000;
console.log(foo.numberFormat(2)); // us format: 5,000.00
console.log(foo.numberFormat(2, ',', '.')); // european format: 5.000,00

я обнаружил, что мне часто нужно вернуть число для математических операций, но parseFloat преобразует 5,000 в 5, просто принимая первую последовательность целочисленных значений. Поэтому я создал свою собственную функцию преобразования float и добавил ее в прототип строки.

String.prototype.getFloat = function(dec_point, thousands_sep) {
    dec_point = typeof dec_point !== 'undefined' ? dec_point : '.';
    thousands_sep = typeof thousands_sep !== 'undefined' ? thousands_sep : ',';

    var parts = this.split(dec_point);
    var re = new RegExp("[" + thousands_sep + "]");
    parts[0] = parts[0].replace(re, '');

    return parseFloat(parts.join(dec_point));
}

теперь вы можете использовать обе функции следующим образом:

var foo = 5000;
var fooString = foo.numberFormat(2); // The string 5,000.00
var fooFloat = fooString.getFloat(); // The number 5000;

console.log((fooString.getFloat() + 1).numberFormat(2)); // The string 5,001.00

Intl.NumberFormat

собственная функция JS. Поддерживается IE11, Edge, последним Safari, Chrome, Firefox, Opera, Safari на iOS и Chrome на Android.

var number = 3500;

console.log(new Intl.NumberFormat().format(number));
// → '3,500' if in US English locale

С помощью регулярного выражения

function toCommas(value) {
    return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
console.log(toCommas(123456789)); // 123,456,789
console.log(toCommas(1234567890)); // 1,234,567,890
console.log(toCommas(1234)); // 1,234

использование toLocaleString ()

var number = 123456.789;

// request a currency format
console.log(number.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' }));
// → 123.456,79 €

// the Japanese yen doesn't use a minor unit
console.log(number.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' }))
// → ¥123,457

// limit to three significant digits
console.log(number.toLocaleString('en-IN', { maximumSignificantDigits: 3 }));
// → 1,23,000

ref MDN: номер.прототип.методом tolocalestring()

Использование Intl.NumberFormat()

var number = 123456.789;

console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(number));
// expected output: "123.456,79 €"

// the Japanese yen doesn't use a minor unit
console.log(new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }).format(number));
// expected output: "¥123,457"

// limit to three significant digits
console.log(new Intl.NumberFormat('en-IN', { maximumSignificantDigits: 3 }).format(number));
// expected output: "1,23,000"

ref Intl.NumberFormat

ДЕМО ЗДЕСЬ

<script type="text/javascript">
  // Using Regular expression
  function toCommas(value) {
    return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  }

  function commas() {
    var num1 = document.myform.number1.value;

    // Using Regular expression
    document.getElementById('result1').value = toCommas(parseInt(num1));
    // Using toLocaleString()
    document.getElementById('result2').value = parseInt(num1).toLocaleString('ja-JP', {
      style: 'currency',
      currency: 'JPY'
    });
    // Using Intl.NumberFormat()
    document.getElementById('result3').value = new Intl.NumberFormat('ja-JP', {
      style: 'currency',
      currency: 'JPY'
    }).format(num1);
  }
</script>
<FORM NAME="myform">
  <INPUT TYPE="text" NAME="number1" VALUE="123456789">
  <br>
  <INPUT TYPE="button" NAME="button" Value="=>" onClick="commas()">
  <br>Using Regular expression
  <br>
  <INPUT TYPE="text" ID="result1" NAME="result1" VALUE="">
  <br>Using toLocaleString()
  <br>
  <INPUT TYPE="text" ID="result2" NAME="result2" VALUE="">
  <br>Using Intl.NumberFormat()
  <br>
  <INPUT TYPE="text" ID="result3" NAME="result3" VALUE="">

</FORM>

Я думаю, что это самое короткое регулярное выражение, которое это делает:

/\B(?=(\d{3})+\b)/g

"123456".replace(/\B(?=(\d{3})+\b)/g, ",")

Я проверил его на нескольких числах, и это сработало.


Number.prototype.toLocaleString() было бы здорово, если бы он был предоставлен изначально всеми браузерами (Safari).

Я проверил все остальные ответы, но никто, казалось, не заполнял его. Вот poc к тому, что на самом деле является комбинацией первых двух ответов; если toLocaleString works он использует его, если он не использует пользовательскую функцию.

var putThousandsSeparators;

putThousandsSeparators = function(value, sep) {
  if (sep == null) {
    sep = ',';
  }
  // check if it needs formatting
  if (value.toString() === value.toLocaleString()) {
    // split decimals
    var parts = value.toString().split('.')
    // format whole numbers
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, sep);
    // put them back together
    value = parts[1] ? parts.join('.') : parts[0];
  } else {
    value = value.toLocaleString();
  }
  return value;
};

alert(putThousandsSeparators(1234567.890));

разделитель тысяч может быть вставлен в международной дружественной манере с помощью браузера


Если вы имеете дело со значениями валюты и форматированием много, то, возможно, стоит добавить tiny Бухгалтерский учет.js который обрабатывает много пограничных случаев и локализации:

// Default usage:
accounting.formatMoney(12345678); // ,345,678.00

// European formatting (custom symbol and separators), could also use options object as second param:
accounting.formatMoney(4999.99, "€", 2, ".", ","); // €4.999,99

// Negative values are formatted nicely, too:
accounting.formatMoney(-500000, "£ ", 0); // £ -500,000

// Simple `format` string allows control of symbol position [%v = value, %s = symbol]:
accounting.formatMoney(5318008, { symbol: "GBP",  format: "%v %s" }); // 5,318,008.00 GBP

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

function commafy( num){
  var parts = (''+(num<0?-num:num)).split("."), s=parts[0], L, i=L= s.length, o='';
  while(i--){ o = (i===0?'':((L-i)%3?'':',')) 
                  +s.charAt(i) +o }
  return (num<0?'-':'') + o + (parts[1] ? '.' + parts[1] : ''); 
}

он показывает многообещающую производительность:http://jsperf.com/number-formatting-with-commas/5

2015.4.26: незначительное исправление для решения проблемы, когда numhttps://jsfiddle.net/runsun/p5tqqvs3/


вы можете использовать эту процедуру для форматирования вашей валюты.

var nf = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});
nf.format(123456.789); // ‘3,456.79’

для получения дополнительной информации, вы можете получить доступ к этой ссылке.

https://www.justinmccandless.com/post/formatting-currency-in-javascript/


вот простая функция, которая вставляет запятые для тысяч сепараторов. Он использует функции массива, а не регулярное выражение.

/**
 * Format a number as a string with commas separating the thousands.
 * @param num - The number to be formatted (e.g. 10000)
 * @return A string representing the formatted number (e.g. "10,000")
 */
var formatNumber = function(num) {
    var array = num.toString().split('');
    var index = -3;
    while (array.length + index > 0) {
        array.splice(index, 0, ',');
        // Decrement by 4 since we just added another unit to the array.
        index -= 4;
    }
    return array.join('');
};

Я написал это, прежде чем наткнуться на этот пост. Нет regex и вы действительно можете понять код.

$(function(){
  
  function insertCommas(s) {

    // get stuff before the dot
    var d = s.indexOf('.');
    var s2 = d === -1 ? s : s.slice(0, d);

    // insert commas every 3 digits from the right
    for (var i = s2.length - 3; i > 0; i -= 3)
      s2 = s2.slice(0, i) + ',' + s2.slice(i);

    // append fractional part
    if (d !== -1)
      s2 += s.slice(d);

    return s2;

  }
  
  
  $('#theDudeAbides').text( insertCommas('1234567.89012' ) );
  
  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="theDudeAbides"></div>

позвольте мне попытаться улучшить uKolka ' s ответ и может помочь другим сэкономить время.

использовать цифра.js.

document.body.textContent = numeral(1234567).format('0,0');
<script src="//cdnjs.cloudflare.com/ajax/libs/numeral.js/1.4.5/numeral.min.js"></script>

вы должны пойти с количество.прототип.методом tolocalestring() только если его совместимость браузера - это не проблема.


для меня лучший ответ-использовать toLocaleString, как сказали некоторые члены. Если вы хотите включить символ"$", просто добавьте параметры languaje и type. Вот и пример для форматирования числа в мексиканские песо

var n = 1234567.22
alert(n.toLocaleString("es-MX",{style:"currency", currency:"MXN"}))

ярлык

1234567.22.toLocaleString("es-MX",{style:"currency", currency:"MXN"})

Я думаю, что эта функция позаботится обо всех проблемах, связанных с этой проблемой.

function commaFormat(inputString) {
    inputString = inputString.toString();
    var decimalPart = "";
    if (inputString.indexOf('.') != -1) {
        //alert("decimal number");
        inputString = inputString.split(".");
        decimalPart = "." + inputString[1];
        inputString = inputString[0];
        //alert(inputString);
        //alert(decimalPart);

    }
    var outputString = "";
    var count = 0;
    for (var i = inputString.length - 1; i >= 0 && inputString.charAt(i) != '-'; i--) {
        //alert("inside for" + inputString.charAt(i) + "and count=" + count + " and outputString=" + outputString);
        if (count == 3) {
            outputString += ",";
            count = 0;
        }
        outputString += inputString.charAt(i);
        count++;
    }
    if (inputString.charAt(0) == '-') {
        outputString += "-";
    }
    //alert(outputString);
    //alert(outputString.split("").reverse().join(""));
    return outputString.split("").reverse().join("") + decimalPart;
}

var formatNumber = function (number) {
  var splitNum;
  number = Math.abs(number);
  number = number.toFixed(2);
  splitNum = number.split('.');
  splitNum[0] = splitNum[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return splitNum.join(".");
}

я добавил tofixed в Aki143S'ы. Это решение использует точки для тысяч разделителей и запятую для точности.

function formatNumber( num, fixed ) { 
    var decimalPart;

    var array = Math.floor(num).toString().split('');
    var index = -3; 
    while ( array.length + index > 0 ) { 
        array.splice( index, 0, '.' );              
        index -= 4;
    }

    if(fixed > 0){
        decimalPart = num.toFixed(fixed).split(".")[1];
        return array.join('') + "," + decimalPart; 
    }
    return array.join(''); 
};

примеры:

formatNumber(17347, 0)  = 17.347
formatNumber(17347, 3)  = 17.347,000
formatNumber(1234563.4545, 3)  = 1.234.563,454

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

Я проверил спецификации CSS 3, чтобы узнать, можно ли это сделать в CSS, но если вы не хотите, чтобы каждая цифра была собственной <span>, Я не думаю, что это возможно.

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

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


много хороших ответов уже. Вот еще, просто для удовольствия:

function format(num, fix) {
    var p = num.toFixed(fix).split(".");
    return p[0].split("").reduceRight(function(acc, num, i, orig) {
        if ("-" === num && 0 === i) {
            return num + acc;
        }
        var pos = orig.length - i - 1
        return  num + (pos && !(pos % 3) ? "," : "") + acc;
    }, "") + (p[1] ? "." + p[1] : "");
}

примеры:

format(77.03453, 2); // "77.03"
format(78436589374); // "78,436,589,374"
format(784, 4);      // "784.0000"
format(-123456);     // "-123,456"

вот моя попытка:

EDIT: добавлено в десятичных дробях

function splitMille(n, separator = ',') {
  // Cast to string
  let num = (n + '')

  // Test for and get any decimals (the later operations won't support them)
  let decimals = ''
  if (/\./.test(num)) {
    // This regex grabs the decimal point as well as the decimal numbers
    decimals = num.replace(/^.*(\..*)$/, '')
  }
  
  // Remove decimals from the number string
  num = num.replace(decimals, '')
    // Reverse the number string through Array functions
    .split('').reverse().join('')
    // Split into groups of 1-3 characters (with optional supported character "-" for negative numbers)
    .match(/[0-9]{1,3}-?/g)
    // Add in the mille separator character and reverse back
    .join(separator).split('').reverse().join('')

  // Put the decimals back and output the formatted number
  return `${num}${decimals}`
}

let testA = splitMille(1234)
let testB = splitMille(-1234)
let testC = splitMille(123456.789)
let testD = splitMille(9007199254740991)
let testE = splitMille(1000.0001)

console.log('Results!\n\tA: %s\n\tB: %s\n\tC: %s\n\tD: %s\n\tE: %s', testA, testB, testC, testD, testE)

Не найдя здесь современного и всеобъемлющего решения, я написал функцию стрелки (без регулярного выражения) для решения проблемы форматирования, и она позволяет вызывающему абоненту предоставить номер часть цифры а также срок и разделитель для Европы и остального мира.

примеры:

numberFormatter(1234567890.123456) => 1,234,567,890
numberFormatter(1234567890.123456, 4) => 1,234,567,890.1235
numberFormatter(1234567890.123456, 4, '.', ',') => 1.234.567.890,1235 Europe

вот функция, записанная в ES6 (современный синтаксис):

const numberFormatter = (number, fractionDigits = 0, thousandSeperator = ',', fractionSeperator = '.') => {
    if (number!==0 && !number || !Number.isFinite(number)) return number
    const frDigits = Number.isFinite(fractionDigits)? Math.min(Math.max(fractionDigits, 0), 7) : 0
    const num = number.toFixed(frDigits).toString()

    const parts = num.split('.')
    let digits = parts[0].split('').reverse()
    let sign = ''
    if (num < 0) {sign = digits.pop()}
    let final = []
    let pos = 0

    while (digits.length > 1) {
        final.push(digits.shift())
        pos++
        if (pos % 3 === 0) {final.push(thousandSeperator)}
    }
    final.push(digits.shift())
    return `${sign}${final.reverse().join('')}${frDigits > 0 ? fractionSeperator : ''}${frDigits > 0 && parts[1] ? parts[1] : ''}`
}

Это был проверено на отрицательный, плохой вход и случаи NaN. Если вход Нэн затем он просто возвращает его.


решение от @user1437663 отлично.

кто действительно понимает, решение готовится понимать сложные регулярные выражения.

небольшое улучшение, чтобы сделать его более читабельным:

function numberWithCommas(x) {
    var parts = x.toString().split(".");
    return parts[0].replace(/\B(?=(\d{3})+(?=$))/g, ",") + (parts[1] ? "." + parts[1] : "");
}

шаблон начинается с \B чтобы избежать использования запятой в начале слова. Интересно, что шаблон возвращается пустым, потому что \B не аванс "курсор" (то же самое относится к $).

O \B сопровождается менее известными ресурсами, но является мощной функцией регулярных выражений Perl.

            Pattern1 (? = (Pattern2) ).

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

В этом случае pattern2 is

\d{3})+(?=$)

это означает 3 цифры (один или несколько раз), за которыми следует конец строки ($)

наконец, заменить метод изменяет все вхождения найденного шаблона (пустая строка) для запятой. Это происходит только в тех случаях, когда оставшаяся часть делится на 3 цифры (такие случаи, когда будущий курсор достигает конца источника).


вот хорошее решение с меньшим количеством кодирования...

var y = "";
var arr = x.toString().split("");
for(var i=0; i<arr.length; i++)
{
    y += arr[i];
    if((arr.length-i-1)%3==0 && i<arr.length-1) y += ",";
}

альтернативный способ, поддерживающий десятичные дроби, различные сепараторы и негативы.

var number_format = function(number, decimal_pos, decimal_sep, thousand_sep) {
    var ts      = ( thousand_sep == null ? ',' : thousand_sep )
        , ds    = ( decimal_sep  == null ? '.' : decimal_sep )
        , dp    = ( decimal_pos  == null ? 2   : decimal_pos )

        , n     = Math.abs(Math.ceil(number)).toString()

        , i     = n.length % 3 
        , f     = n.substr(0, i)
    ;

    if(number < 0) f = '-' + f;

    for(;i<n.length;i+=3) {
        if(i!=0) f+=ts;
        f+=n.substr(i,3);
    }

    if(dp > 0) 
        f += ds + number.toFixed(dp).split('.')[1]

    return f;
}

я адаптировал ваш код для работы в текстовом поле (Тип ввода="текст"), чтобы мы могли вводить и удалять цифры в режиме реального времени без потери курсора. Это работает также, если вы выбираете range при удалении. И вы можете использовать стрелки и кнопки home/end свободно.
Спасибо, что сэкономили мое время!

//function controls number format as "1,532,162.3264321"
function numberWithCommas(x) {
    var e = e || window.event;
    if (e.keyCode >= '35' && e.keyCode <= '40') return; //skip arrow-keys
    var selStart = x.selectionStart, selEnd = x.selectionEnd; //save cursor positions
    var parts = x.value.toString().split(".");
    var part0len = parts[0].length; //old length to check if new ',' would be added. Need for correcting new cursor position (+1 to right).

    //if user deleted ',' - remove previous number instead (without selection)
    if (x.selectionLength == 0 && (e.keyCode == 8 || e.keyCode == 46)) {//if pressed 8-backspace or 46-delete button
        var delPos = parts[0].search(/\d{4}/);
        if (delPos != -1) {//if found 4 digits in a row (',' is deleted)
            if (e.keyCode == 8) {//if backspace flag
                parts[0] = parts[0].slice(0, selStart - 1) + parts[0].slice(selEnd, parts[0].length);
                selEnd--;
                if (selStart > selEnd) selStart = selEnd;
            } else {
                parts[0] = parts[0].slice(0, selStart) + parts[0].slice(selEnd + 1, parts[0].length);
                selStart++;
                if (selEnd < selStart) selEnd = selStart;
            }
        }
    }

   var hasMinus = parts[0][0] == '-';
   parts[0] = (hasMinus ? '-' : '') + parts[0].replace(/[^\d]*/g, ""); //I'd like to clear old ',' to avoid things like 1,2,3,5,634.443216
   parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); //sets ',' between each 3 digits
   if (part0len < parts[0].length) { //move cursor to right if added new ','
       selStart++;
       selEnd++;
   } else if (part0len > parts[0].length) { //..or if removed last one ','
       selStart--;
       selEnd--;
   }
   x.value = parts.join(".");
   x.setSelectionRange(selStart, selEnd); //restoring cursor position
}
function saveSelectionLength(x) {
    x.selectionLength = x.selectionEnd - x.selectionStart;
}

чтобы использовать это, просто добавили два события-onKeyUp и onKeyDown

<asp:TextBox runat="server" ID="val" Width="180px" onKeyUp="numberWithCommas(this);" onKeyDown="saveSelectionLength(this);"/>