自定义过滤器,空格为千位分隔符无法正常工作

时间:2017-10-31 15:33:22

标签: javascript regex string numbers

我正在尝试编写自定义过滤器,以便在我的应用程序中以xxx xxx,xxx格式过滤数字。

这是我到目前为止所写的功能:

var formatNumber = function(input, fractionSeparator, thousandsSeparator, fractionSize) {
    fractionSeparator = fractionSeparator || ',';
    thousandsSeparator = thousandsSeparator || ' ';
    fractionSize = fractionSize || 3;     
    var output = '', parts = [];

    input = input.toString();
    parts = input.split(".");
    output = parts[0].replace(/(\d{3})/g, ""+ thousandsSeparator +"$1").trim();
    if(parts.length>1){
        output += fractionSeparator;
        output += parts[1].substring(0, fractionSize);
    }       
    return output;
};

实际上,此功能对某些数字非常有效,但在其他情况下失败,例如:

使用以下数字:

  • 对于451.585478,它会打印451,585
  • 对于154455451.58,它会打印154 455 451,58

这些例子失败:

  • 对于54455451.58,它会打印54455 451,58

  • 对于55451.58,它会打印55451,58

演示:



var formatNumber = function(input, fractionSeparator, thousandsSeparator, fractionSize) {
  fractionSeparator = fractionSeparator || ',';
  thousandsSeparator = thousandsSeparator || ' ';
  fractionSize = fractionSize || 3;
  var output = '',
    parts = [];

  input = input.toString();
  parts = input.split(".");
  output = parts[0].replace(/(\d{3})/g, "" + thousandsSeparator + "$1").trim();
  if (parts.length > 1) {
    output += fractionSeparator;
    output += parts[1].substring(0, fractionSize);
  }
  return output;
};

console.log(formatNumber(154455451.58));

console.log(formatNumber(55451.58));
console.log(formatNumber(54455451.58));




我不知道它有什么问题。任何帮助将不胜感激。

编辑:

我终于得到了它的工作,问题出在我的正则表达式,这是我用来格式化数千的最终正则表达式:

output = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandsSeparator).trim();

这是最终的代码:



var formatNumber = function(input, fractionSeparator, thousandsSeparator, fractionSize) {

  fractionSeparator = fractionSeparator || ',';
  thousandsSeparator = thousandsSeparator || ' ';
  fractionSize = fractionSize || 3;
  var output = '',
    parts = [];

  input = input.toString();
  parts = input.split(".");
  output = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandsSeparator).trim();
  if (parts.length > 1) {
    output += fractionSeparator;
    output += parts[1].substring(0, fractionSize);
  }
  return output;
};

console.log(formatNumber(154455451.58));

console.log(formatNumber(55451.58));
console.log(formatNumber(54455451.58));




3 个答案:

答案 0 :(得分:1)

问题在于:

output = parts[0].replace(/(\d{3})/g, ""+ thousandsSeparator +"$1").trim();

您在每3个数字之前插入空格(我会在括号之间标记匹配):

"(123)(456)78" --> "( 123)( 456)78"

然后你正在修剪它 - > "123 45678"

你的想法很好,但你必须从右到左开始这样做,所以我会反转parts[0]和替换:

parts[0] = parts[0].split('').reverse().join('');
"12345678" --> "87654321"

parts[0] = parts[0].replace(/(\d{3})/g, "$1" + thousandsSeparator).trim();
"(876)(543)21" --> "(876 )(543 )21"

output = parts[0].split('').reverse().join('');
"876 543 21" --> "12 345 678"

您想要的输出是什么。这是更新的代码段:

var formatNumber = function(input, fractionSeparator, thousandsSeparator, fractionSize) {
  fractionSeparator = fractionSeparator || ',';
  thousandsSeparator = thousandsSeparator || ' ';
  fractionSize = fractionSize || 3;
  var output = '',
    parts = [];

  input = input.toString();
  parts = input.split(".");
  
  parts[0] = parts[0].split('').reverse().join('');
  parts[0] = parts[0].replace(/(\d{3})/g, "$1" + thousandsSeparator).trim();
  output = parts[0].split('').reverse().join('');
  
  if (parts.length > 1) {
    output += fractionSeparator;
    output += parts[1].substring(0, fractionSize);
  }
  return output;
};

console.log(formatNumber(154455451.58));

console.log(formatNumber(55451.58));
console.log(formatNumber(54455451.58));

答案 1 :(得分:1)

您可以在.上拆分号码,然后拆分它并将其转换为数组,并可以使用array#maparray#filter获取一个新数组,其元素分组为块3然后你必须reversejoin它后退

const formatNumber = (num, fractionSeparator, thousandsSeparator, fractionSize) => {
  fractionSeparator = fractionSeparator || ',';
  thousandsSeparator = thousandsSeparator || ' ';
  fractionSize = fractionSize || 3;
  let [first, second] = num.toString().split('.');
  let reversed = first.split('').reverse();
  reversed = reversed.map((e,i) => i%fractionSize===0 ? reversed.slice(i,i+fractionSize).join('') :null)
          .filter(x => x)
          .reverse()
          .join(thousandsSeparator);
  return reversed + fractionSeparator + second;
}

console.log(formatNumber(154455451.58));
console.log(formatNumber(55451.58));
console.log(formatNumber(54455451.58));

答案 2 :(得分:1)

这是另一种基于我曾经写过的“货币格式化程序”方法的方法:

var sRegexFormatPattern = '^([^\\' + thousandsSeparator +
                          '\.]+)(\\d{3}[\\' + thousandsSeparator +
                          '\.]|\\d{3}$)';
var regexFormatPattern = new RegExp(sRegexFormatPattern);

while (regexFormatPattern.test(input)) {
    input = input.replace(regexFormatPattern, '$1' + thousandsSeparator + '$2');
}

让我们从后到前打破正则表达式。 。

  • 第二个捕获组((\\d{3}[\\' + thousandsSeparator + '\.]|\\d{3}$))恰好匹配3位数字和小数点(\d{3}\.),传入的字符为“千位分离器”(\d{3}\THOUSANDS_SEPARATOR ),或字符串的结尾(\d{3}$)。

  • 第一个捕获组(^([^\\' + thousandsSeparator + '\.]+))匹配所有字符(都是数字... ...您需要单独检查以确保这一点)不是小数点,也不是作为“千位分离器”传入的字符,直到它击中第二个捕获组

注意:我在“千位分隔符”之前添加了一个转义斜杠,以防万一有人在正则表​​达式中输入了另一个含义的东西,但是,即便如此,某些字符也可能导致问题。执行正则表达式。 。 。需要更多地调查它以使其万无一失。

只要它能在值中找到这两个部分,它就会用“千位分隔符”将它们分解并再次检查。以“12345678.90”为例,迭代如下:

  • 12345 678. ---将数字更改为---> 12345 678.90
  • 12 345 678. ---将数字更改为---> 12 345 678.90

该部分之前和之后的所有内容或多或少都是您已有的。 。 。我添加了一个小调整,你是如何格式化字符串的“分数”部分,但其余部分几乎相同(请参阅下面的完整JS代码)。

使用您的测试值,我得到了:

- 451.585478 --->           451,585
- 154455451.58 ---> 154 455 451,58
- 54455451.58 --->   54 455 451,58
- 55451.58 --->          55 451,58

<强>样本

$("document").ready(function() {
  $(".formattingInput").on("change", function() {
    $("#formattedNumber").text(formatNumber(
      $("#unformattedNumberInput").val(),
      $("#fractionSeparator").val(),
      $("#thousandsSeparator").val(),
      $("#fractionSize").val()
    ));
  });
});

var formatNumber = function(input, fractionSeparator, thousandsSeparator, fractionSize) {
  fractionSeparator = fractionSeparator || ',';
  thousandsSeparator = thousandsSeparator || ' ';
  fractionSize = fractionSize || 3;

  var sRegexFormatPattern = '^([^\\' + thousandsSeparator +
    '\.]+)(\\d{3}[\\' + thousandsSeparator +
    '\.]|\\d{3}$)';
  var regexFormatPattern = new RegExp(sRegexFormatPattern);

  while (regexFormatPattern.test(input)) {
    input = input.replace(regexFormatPattern, '$1' + thousandsSeparator + '$2');
  }

  var parts = input.split('.');

  if (parts.length > 1) {
    input = parts[0] +
      fractionSeparator +
      parts[1].substring(0, fractionSize);
  }

  return (input.length > 0) ? input : 'Please input a value in the "Number" field.';
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div>
  <label for="unformattedNumberInput">Number: <input type="text" id="unformattedNumberInput" class="formattingInput" /></label><br />
  <label for="thousandsSeparator">Thousands Separator: <input type="text" id="thousandsSeparator" class="formattingInput" /></label><br />
  <label for="fractionSeparator">Fraction Separator: <input type="text" id="fractionSeparator" class="formattingInput" /></label><br />
  <label for="fractionSize">Fraction Size: <input type="text" id="fractionSize" class="formattingInput" /></label><br /><br />
</div>

<div>
  <strong>Result:</strong>
  <span id="formattedNumber">Please input a value in the "Number" field.</span>
</div>