Как напечатать число с запятыми в качестве разделителей тысяч в JavaScript - PullRequest
1445 голосов
/ 25 мая 2010

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

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

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

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

Ответы [ 44 ]

5 голосов
/ 10 июня 2017
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(".");
}

EDIT: Функция работает только с положительным числом. для примера:

var number = -123123231232;
formatNumber(number)

Выход: "123,123,231,232"

Но для ответа на вопрос выше * метод 1007 * просто решает проблему.

var number = 123123231232;
    number.toLocaleString()

Выход: "123,123,231,232"

унывайте!

4 голосов
/ 19 ноября 2012

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

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;
}
3 голосов
/ 26 сентября 2012

Я добавил 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
3 голосов
/ 08 января 2014

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

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"
2 голосов
/ 25 мая 2010

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

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

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

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

2 голосов
/ 14 июня 2019

My « true » решение только для регулярных выражений для тех, кто любит однострочники

Вы видите этих восторженных игроков выше? Может быть, вы можете играть в гольф из этого. Вот мой инсульт.

n => `${n}`.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " ").replace(/(?<=\.(\d{3})+)\B/g, " ")

Использует ТОНКОЕ ПРОСТРАНСТВО (U + 2009) для разделителя тысяч, как Международная система единиц в восьмом издание (2006) их публикации « Брошюра СИ: Международная система единиц (СИ) » (см. §5.3.4.). Девятое издание (2019) предлагает использовать для него пробел (см. §5.4.4.). Вы можете использовать все, что хотите, включая запятую.


См.

const integer_part_only = n => `${n}`.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " I ");
const fractional_part_only = n => `${n}`.replace(/(?<=\.(\d{3})+)\B/g, " F ");
const both = n => fractional_part_only(integer_part_only(n));

function demo(number) { // I’m using Chrome 74.
	console.log(`${number}
		→ "${integer_part_only(number)}" (integer part only)
		→ "${fractional_part_only(number)}" (fractional part only)
		→ "${both(number)}" (both)
	`);
}
demo(Math.random() * 10e5);
demo(123456789.01234567);
demo(123456789);
demo(0.0123456789);

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

Для целой части

.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " I ")
  • .replace(……, " I ") Поставьте «Я»
    • /……/g на каждом из
      • \B между двумя соседними цифрами
        • (?=……) ПОЗИТИВНО LOOKAHEAD чья правая часть
          • (\d{3})+ один или несколько трехзначных блоков
          • \b, за которым следует нецифровка, такая как точка, конец строки и т. Д.,
        • (?<!……) ОТРИЦАТЕЛЬНЫЙ СМОТРЕТЬ исключая те, чья левая часть
          • \.\d+ - точка, за которой следуют цифры («имеет десятичный разделитель»).

Для десятичной части

.replace(/(?<=\.(\d{3})+)\B/g, " F ")
  • .replace(……, " F ") Поставить «F»
    • /……/g на каждом из
      • \B между двумя соседними цифрами
        • (?<=……) ПОЗИТИВНО СМОТРЕТЬ , чья левая часть
          • \. десятичный разделитель
          • (\d{3})+, за которым следуют один или несколько трехзначных блоков.

Классы символов и Границы

\d

Соответствует любой цифре (арабская цифра). Эквивалент [0-9].

Например,

  • /\d/ или /[0-9]/ соответствует 2 в B2 is the suite number.

\b

Соответствует границе слова . Это позиция, где за символом слова не следует или не предшествует другой символ слова, например между буквой и пробелом. Обратите внимание, что соответствующая граница слова не включена в соответствие. Другими словами, длина совпадающей границы слова равна нулю.

Примеры:

  • /\bm/ соответствует m в moon;
  • /oo\b/ не соответствует oo в moon, потому что за oo следует n, который является символом слова;
  • /oon\b/ соответствует oon в moon, поскольку oon является концом строки, поэтому за ним не следует символ слова;
  • /\w\b\w/ никогда не будет соответствовать чему-либо, потому что за символом слова никогда не может следовать ни слово, ни слово.

\B

Соответствует границе без слов . Это позиция, в которой предыдущий и следующий символ имеют одинаковый тип: либо оба должны быть словами, либо оба должны быть не словами. Например, между двумя буквами или между двумя пробелами. Начало и конец строки считаются не словами. То же, что и совпадающая граница слова, совпадающая граница не из слов также не включена в совпадение.

Например,

  • /\Bon/ соответствует on в at noon;
  • /ye\B/ соответствует ye в possibly yesterday.

Совместимость браузера

2 голосов
/ 14 июля 2014

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

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     = ((number < 0) ? '-' : '') + fn.substr(0, i)
    ;

    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;
}
2 голосов
/ 13 января 2013

Решение от @ 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 цифры (один или несколько раз), за которыми следует конец строки ($)

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

2 голосов
/ 15 марта 2019

Только для будущих Googlers (или не обязательно «Googlers»):

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

Итак, да, вы можете использовать некоторые из предложенных вариантов или даже написать что-нибудь примитивное, но полезное, например:

const strToNum = str => {

   //Find 1-3 digits followed by exactly 3 digits & a comma or end of string
   let regx = /(\d{1,3})(\d{3}(?:,|$))/;
   let currStr;

   do {
       currStr = (currStr || str.split(`.`)[0])
           .replace( regx, `$1,$2`)
   } while (currStr.match(regx)) //Stop when there's no match & null's returned

   return ( str.split(`.`)[1] ) ?
           currStr.concat(`.`, str.split(`.`)[1]) :
           currStr;

};

strToNum(`123`) // => 123
strToNum(`123456`) // => 123,456
strToNum(`-1234567.0987`) // => -1,234,567.0987

Регулярное выражение, которое здесь используется, довольно просто, и цикл будет идти ровно столько раз, сколько потребуется для выполнения работы.

И вы могли бы оптимизировать его гораздо лучше, код "DRYify" и т. Д.

Пока,

(-1234567.0987).toLocaleString();

(в большинстве ситуаций) будет гораздо лучшим выбором.

Дело не в скорости выполнения и не в кросс-браузерной совместимости.

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

Этот метод в соответствии с документацией ECMAScript был введен в 1999 году, и я полагаю, что причиной этого была надежда, что Интернет в какой-то момент соединит людей во всем мире, поэтому потребовались некоторые инструменты "интернализации".

Сегодня Интернет соединяет всех нас, поэтому важно помнить, что мир намного сложнее, чем мы можем себе представить, и (/ почти) все мы здесь , в Интернет.

Очевидно, что, учитывая разнообразие людей, невозможно гарантировать идеальный UX для всех, потому что мы говорим на разных языках, ценим разные вещи и т. Д. И именно из-за этого еще более важно попытаться локализовать вещи настолько, насколько это возможно. как это возможно.

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

Для меня использование RegExp вместо .toLocaleString () в подобной ситуации немного похоже на создание приложения для часов с JavaScript и его жесткое программирование таким образом, чтобы оно отображало только пражское время (что будет совершенно бесполезно для людей, которые не живут в Праге), хотя поведение по умолчанию

new Date();

- вернуть данные в соответствии с конечными часами пользователя.

1 голос
/ 23 марта 2015

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

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