正则表达式用逗号分隔数千并保留两位小数

时间:2017-04-11 08:08:30

标签: javascript jquery regex

我最近在回答另一个StackOverflow问题时想出了这段代码。基本上,在模糊时,这段代码将正确地用逗号分隔数千,并将十进制数保留为两位数(如美元的编写方式[7,745.56])。

我想知道是否有更简洁的方法使用正则表达式来分隔和切断过多的小数位。我最近用最近的尝试更新了这篇文章。使用正则表达式有更好的方法吗?

输入 - >目标输出

var result;
var str = []
reg = new RegExp(/(\d*(\d{2}\.)|\d{1,3})/, "gi");
reversed = "9515321312.2323432".split("").reverse().join("")
while (result = reg.exec(reversed)) {
  str.push(result[2] ? result[2] : result[0])
}
console.log(str.join(",").split("").reverse().join("").replace(",.","."))

当前正则表达式



ng-options="(listRef.name + ' ' + listRef.id) as listRef.id for listRef in list"




9 个答案:

答案 0 :(得分:7)

作为Regex的替代方案,您可以使用以下方法

Number(num.toFixed(2)).toLocaleString('en-US')

num.toLocaleString('en-US', {maximumFractionDigits: 2})

你仍然会拥有toFixed(2),但它非常干净。 toFixed(2) {maximumFractionDigits: 2}虽然不想让你想要这个数字。与toLocaleString相同,也是var nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22] for (var num of nums) console.log(num, '->', Number(num.toFixed(2)).toLocaleString('en-US') )的第二个参数。



(num * 100 | 0) / 100




像您展示的那样覆盖这个数字有点棘手。像|0这样的事情不起作用。计算失去精确度(例如,在某些情况下,.99将变为.98)。 (Math.floor()也不会使用更大的数字,但即使function format(num) { var num = num.toLocaleString('en-US') var end = num.indexOf('.') < 0 ? num.length : num.indexOf('.') + 3 return num.substring(0, end) } 也存在精度问题。)

解决方案是将数字视为字符串。

var nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22]

for (var num of nums) console.log(num, '->', format(num))

function format(num) {
  var num = num.toLocaleString('en-US')
  var end = num.indexOf('.') < 0 ? num.length : num.indexOf('.') + 3
  return num.substring(0, end)
}

&#13;
&#13;
'en-US'
&#13;
&#13;
&#13;

(当更改为.以外的其他格式时,请注意数字,,因为某些语言使用toLocaleString('en-US')作为分形分隔符

对于兼容性,根据CanIUse <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:card_view="http://schemas.android.com/tools" android:id="@+id/card_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:cardBackgroundColor="@color/Grey_50" app:cardCornerRadius="0dp" app:cardUseCompatPadding="true" card_view:cardCornerRadius="dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="rtl"> <ImageView android:id="@+id/image_news" android:layout_width="60dp" android:layout_height="60dp" android:layout_gravity="end" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:scaleType="fitXY" /> <TextView android:id="@+id/txt_news_title" android:layout_width="match_parent" android:layout_gravity="start" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toLeftOf="@+id/image_news" android:layout_toStartOf="@+id/image_news" android:layout_marginRight="3dp" android:textSize="13sp" /> <View android:id="@+id/view1" android:layout_below="@+id/image_news" android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="10dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/recent" android:layout_width="15dp" android:layout_height="15dp" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_gravity="center" android:layout_marginRight="2dp" android:background="@drawable/ic_recent" android:textAlignment="center" /> <TextView android:id="@+id/txt_timedate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toEndOf="@+id/recent" android:layout_toRightOf="@+id/recent" android:text="20:49" android:textColor="@color/Grey_600" android:textSize="16sp" /> </LinearLayout> </RelativeLayout> </android.support.v7.widget.CardView>

  

有效支持所有浏览器(自IE6 +,Firefox 2 +,Chrome   1+等)

答案 1 :(得分:5)

如果你真的坚持纯正在使用正则表达式(并截断而不是舍入小数位),我能想到的唯一解决方案是使用替换函数作为.replace()的第二个参数:

('' + num).replace(
  /(\d)(?=(?:\d{3})+(?:\.|$))|(\.\d\d?)\d*$/g, 
  function(m, s1, s2){
    return s2 || (s1 + ',');
  }
);

这会使您的所有测试用例通过:

&#13;
&#13;
function format(num){
  return ('' + num).replace(
    /(\d)(?=(?:\d{3})+(?:\.|$))|(\.\d\d?)\d*$/g, 
    function(m, s1, s2){
      return s2 || (s1 + ',');
    }
  );
}


test(7456, "7,456");
test(45345, "45,345");
test(25.23523534, "25.23"); //truncated, not rounded
test(3333.239, "3,333.23"); //truncated, not rounded
test(234.99, "234.99");
test(2300.99, "2,300.99");
test(23123123123.22, "23,123,123,123.22");

function test(num, expected){
  var actual = format(num);
  console.log(num + ' -> ' + expected + ' => ' + actual + ': ' + 
    (actual === expected ? 'passed' : 'failed')
   );
}
&#13;
&#13;
&#13;

答案 2 :(得分:3)

我添加了另一个图层,其中正则表达式在您的正则表达式逗号添加逻辑的基础上将不需要的小数点数降低到百分之一以下;

val.replace(/(\.\d{2})\d*/, "$1").replace(/(\d)(?=(\d{3})+\b)/g, "$1,")

&#13;
&#13;
doIt("7456");
doIt("45345");
doIt("25.23523534");
doIt("3333.239");
doIt("234.99");
doIt("2300.99");
doIt("23123123123.22");
doIt("5812090285.2817481974897");

function doIt(val) {
    console.log(val + " -> " + val.replace(/(\.\d{2})\d*/, "$1").replace(/(\d)(?=(\d{3})+\b)/g, "$1,"));
}
&#13;
&#13;
&#13;

如果多次调用regex替换是正常的,那么这个答案应该让你满意,因为它只有正则表达式替换逻辑而没有别的。

答案 3 :(得分:2)

尝试:

var n = 5812090285.2817481974897;
n = n.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
console.log(n);

输出:

5,812,090,285.28

注意:.toFixed(2)会返回string。因此,为了进一步简化此操作,您必须在执行正则表达式之前添加一种将n转换为string的方法。例如:

n.toString.replace(/(\d)(?=(\d{3})+\.)/g, '$1,');  //ofc with the additional regex

虽然您认为在javascript中无关紧要,但显然在这种情况下会这样做。所以我不知道不使用会有多“混乱”。

答案 4 :(得分:2)

RegEx再次营救!

我的解决方案有两个部分:

  

.toFixed:用于限制小数限制

     

/(\d)(?=(\d\d\d)+(?!\d))/g:它一次使用三位数的后向引用

这里放了一切:

// .toFixed((/\./g.test(num)) ? 2 : 0) it tests if the input number has any decimal places, if so limits it to 2 digits and if not, get's rid of it altogether by setting it to 0
num.toFixed((/\./g.test(num)) ? 2 : 0).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"))

你可以在这里看到它:

&#13;
&#13;
var input = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22]

input.forEach(function(num) {
  $('div')
    .append(
      $('<p>').text(num + ' => ' +
        num.toFixed( (/\./g.test(num))?2:0 ).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"))
    );
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div> </div>
&#13;
&#13;
&#13;

注意:我只使用jQuery附加结果

答案 5 :(得分:1)

这是一种没有正则表达式的方法:

value.toLocaleString("en-US", { maximumFractionDigits: 2 })

&#13;
&#13;
function formatValue() {
    var source = document.getElementById("source");
    var output = document.getElementById("output");
    var value = parseFloat(source.value);
    output.innerText = value.toLocaleString("en-US", { maximumFractionDigits: 2 });
}
&#13;
<input id="source" type="text" />
<button onclick="formatValue()">Format</button>
<div id="output"></div>
&#13;
&#13;
&#13;

答案 6 :(得分:1)

你可以这样做

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

这里只是将数字转换为格式化数字,向下舍入到2位小数,然后删除.00(如果存在)。

这可以是您可以使用的一种方法。

var format = function (num) {
    
return (parseFloat(num).toFixed(2)).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,").replace(".00","")
}
$(function () {
    $("#principalAmtOut").blur(function (e) {
        $(this).val(format($(this).val()));
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="principalAmtOut" type="text" />

答案 7 :(得分:1)

您可以使用Intl.NumberFormat style设置为"decimal"maximumFractionDigits设置为2 options传递给第二个参数的对象

const nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22];

const formatOptions = {style:"decimal", maximumFractionDigits:2};
           
const formatter = new Intl.NumberFormat("en-US", formatOptions);

const formatNums = num => formatter.format(num);

let formattedNums = nums.map(formatNums);

console.log(formattedNums);

答案 8 :(得分:0)

我在没有使用toFixed的情况下找到了基于@Pierre答案的解决方案:

&#13;
&#13;
function format(n) {
  n = +n;
  var d = Math.round(n * 100) % 100;
  return (Math.floor(n) + '').replace(/(\d)(?=(\d{3})+$)/g, '$1,') + (d > 9 ? '.' + d : d > 0 ? '.0' + d : '');
}

console.log(format(7456));
console.log(format(7456.0));
console.log(format(7456.1));
console.log(format(7456.01));
console.log(format(7456.001));
console.log(format(45345));
console.log(format(25.23523534));
console.log(format(3333.239));
console.log(format(234.99));
console.log(format(2300.99));
console.log(format(23123123123.22));
console.log(format('23123123123.22'));
&#13;
&#13;
&#13;