简体   繁体   English

使用replace和正则表达式应用货币格式

[英]Applying currency format using replace and a regular expression

I am trying to understand some code where a number is converted to a currency format. 我正在尝试理解一些将数字转换为货币格式的代码。 Thus, if you have 16.9 it converts to $16.90. 因此,如果您有16.9,它将转换为$ 16.90。 The problem with the code is if you have an amount over $1,000, it just returns $1, an amount over $2,000 returns $2, etc. Amounts in the hundreds show up fine. 代码的问题是,如果您的金额超过$ 1,000,则只返回$ 1,金额超过$ 2,000则返回$ 2,依此类推。数百元的金额显示罚款。

Here is the function: 这是函数:

var _formatCurrency = function(amount) {
    return "$" + parseFloat(amount).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
};

(The reason the semicolon is after the bracket is because this function is in itself a statement in another function. That function is not relevant to this discussion.) (分号放在方括号后面的原因是因为此函数本身是另一个函数的声明。该函数与本讨论无关。)

I found out that the person who originally put the code in there found it somewhere but didn't fully understand it and didn't test this particular scenario. 我发现最初将代码放入其中的人在某个地方找到了它,但并没有完全理解它,也没有测试这种特殊情况。 I myself have not dealt much with regular expressions. 我自己对正则表达式的处理不多。 I am not only trying to fix it, but to understand how it is working as it is now. 我不仅在尝试修复它,而且还在理解它的工作原理。

Here's what I've found out. 这是我发现的。 The code between the backslash after the open parenthesis and the backslash before the g is the pattern. 开括号后的反斜杠和g之前的反斜杠之间的代码是模式。 The g means global search. g表示全局搜索。 The \\d means digit, and the (?=\\d{3})+\\. \\d表示数字,而(?=\\d{3})+\\. appears to mean find 3 digits plus a decimal point. 似乎表示找到3位数字加一个小数点。 I'm not sure I have that right, though, because if that was correct shouldn't it ignore numbers like 5.4? 不过,我不确定我是否正确,因为如果正确,它是否不应该忽略5.4之类的数字? That works fine. 很好 Also, I'm not sure what the '$1,' is for. 另外,我不确定'$1,'是干什么的。 It looks to me like it is supposed to be placed where the digits are, but wouldn't that change all the numbers to $1? 在我看来,它应该放在数字的位置,但是那不将所有数字都更改为$ 1吗? Also, why is there a comma after the 1? 另外,为什么在1之后会有逗号?

Assuming that you are working with USD only, then this should work for you as an alternative to Regular Expressions. 假设您只使用美元,那么这应该可以代替正则表达式。 I have also included a few tests to verify that it is working properly. 我还进行了一些测试,以验证它是否正常运行。

 var test1 = '16.9'; var test2 = '2000.5'; var test3 = '300000.23'; var test4 = '3000000.23'; function stringToUSD(inputString) { const splitValues = inputString.split('.'); const wholeNumber = splitValues[0].split('') .map(val => parseInt(val)) .reverse() .map((val, idx, arr) => idx !== 0 && (idx + 1) % 3 === 0 && arr[idx + 1] !== undefined ? `,${val}` : val) .reverse() .join(''); return parseFloat(`${wholeNumber}.${splitValues[1]}`).toFixed(2); } console.log(stringToUSD(test1)); console.log(stringToUSD(test2)); console.log(stringToUSD(test3)); console.log(stringToUSD(test4)); 

The pattern is invalid, and your understanding of the function is incorrect. 该模式无效,并且您对该功能的理解不正确。 This function formats a number in a standard US currency, and here is how it works: 此函数以标准美元格式格式化数字,其工作方式如下:

  1. The parseFloat() function converts a string value to a decimal number. parseFloat()函数将字符串值转换为十进制数。
  2. The toFixed(2) function rounds the decimal number to 2 digits after the decimal point. toFixed(2)函数将十进制数字四舍五入到小数点后的两位数。
  3. The replace() function is used here to add the thousands spearators (ie a comma after every 3 digits). 这里的replace()函数用于添加数千个spearator(即,每3位数字后的逗号)。 The pattern is incorrect, so here is a suggested fix /(\\d)(?=(\\d{3})+\\.)/g and this is how it works: 该模式不正确,因此这是建议的修复程序/(\\d)(?=(\\d{3})+\\.)/g ,这是它的工作方式:
    • The (\\d) captures a digit. (\\d)捕获一个数字。
    • The (?=(\\d{3})+\\.) is called a look-ahead and it ensures that the captured digit above has one set of 3 digits (\\d{3}) or more + followed by the decimal point \\. (?=(\\d{3})+\\.)称为前瞻,它确保上面捕获的数字包含一组3位数字(\\d{3})或更多+后跟小数点\\. after it followed by a decimal point. 之后是小数点。
    • The g flag/modifier is to apply the pattern globally, that is on the entire amount. g标志/修饰符将全局应用模式,即在整个数量上。
    • The replacement $1, replaces the pattern with the first captured group $1 , which is in our case the digit (\\d) (so technically replacing the digit with itself to make sure we don't lose the digit in the replacement) followed by a comma , . 替换$1,将模式替换为第一个捕获的组$1 ,在本例中为数字(\\d) (所以从技术上讲,用数字本身替换数字以确保我们不会在替换中丢失该数字),然后跟一个逗号, So like I said, this is just to add the thousands separator. 就像我说的,这只是添加千位分隔符。

Here are some tests with the suggested fix. 这是一些建议修复的测试。 Note that it works fine with numbers and strings: 请注意,它可以很好地与数字和字符串配合使用:

 var _formatCurrency = function(amount) { return "$" + parseFloat(amount).toFixed(2).replace(/(\\d)(?=(\\d{3})+\\.)/g, '$1,'); }; console.log(_formatCurrency('1')); console.log(_formatCurrency('100')); console.log(_formatCurrency('1000')); console.log(_formatCurrency('1000000.559')); console.log(_formatCurrency('10000000000.559')); console.log(_formatCurrency(1)); console.log(_formatCurrency(100)); console.log(_formatCurrency(1000)); console.log(_formatCurrency(1000000.559)); console.log(_formatCurrency(10000000000.559)); 

Regarding your comment 关于你的评论

I was hoping to just edit the regex so it would work properly. 我希望只编辑正则表达式,使其正常工作。

The regex you are currently using is obviously not working for you so I think you should consider alternatives even if they are not too similar, and 您当前使用的正则表达式显然对您不起作用,因此我认为您应该考虑替代方法,即使它们不太相似,并且

Trying to keep the code change as small as possible 尝试使代码更改尽可能小

Understandable but sometimes it is better to use a code that is a little bit bigger and MORE READABLE than to go with compact and hieroglyphical . 可以理解,但是有时使用比紧凑和象形的代码更大,更易读的代码更好。

Back to business: 重新营业:

I'm assuming you are getting a string as an argument and this string is composed only of digits and may or may not have a dot before the last 1 or 2 digts. 我假设您正在获取一个字符串作为参数,并且该字符串仅由数字组成,并且在最后1或2个数字之前可能没有点。 Something like 就像是

//input     //intended output
1           $1.00
20          $20.00
34.2        $34.20
23.1        $23.10
62516.16    $62,516.16
15.26       $15.26
4654656     $4,654,656.00
0.3         $0.30

I will let you do a pre-check of (assumed) non-valids like 1. | 我将让您对1之类的(假设的)非有效值进行预检查 2.2. 2.2。 | | .6 | .6 | 4.8.1 | 4.8.1 | 4.856 | 4.856 | etc .

Proposed solution: 建议的解决方案:

var _formatCurrency = function(amount) {
    amount = "$" + amount.replace(/(\d)(?=(\d{3})+(\.(\d){0,2})*$)/g, '$1,');

    if(amount.indexOf('.') === -1)
        return amount + '.00';

    var decimals = amount.split('.')[1];

    return decimals.length < 2 ? amount + '0' : amount;
};

Regex break down: 正则表达式细分:

  • (\\d) : Matches one digit. (\\d) :匹配一位数字。 Parentheses group things for referencing when needed. 括号将事物分组以在需要时进行引用。

  • (?=(\\d{3})+(\\.(\\d){0,2})*$) . (?=(\\d{3})+(\\.(\\d){0,2})*$) Now this guy. 现在这个家伙。 From end to beginning: 从头到尾:

    • $ : Matches the end of the string. $ :匹配字符串的结尾。 This is what allows you to match from the end instead of the beginning which is very handy for adding the commas. 这样一来,您就可以从头开始匹配而不是从头开始匹配,这对于添加逗号非常方便。
    • (\\.(\\d){0,2})* : This part processes the dot and decimals. (\\.(\\d){0,2})* :这部分处理点和小数。 The \\. \\. matches the dot. 匹配点。 (\\d){0,2} matches 0, 1 or 2 digits (the decimals). (\\d){0,2}匹配0、1或2位数字(十进制)。 The * implies that this whole group can be empty. *表示整个组可以为空。
    • ?=(\\d{3})+ : \\d{3} matches 3 digits exactly. ?=(\\d{3})+\\d{3}精确匹配3位数字。 + means at least one occurrence . +表示至少出现一次 Finally ?= matches a group after the main expression without including it in the result. 最后, ?=匹配主表达式后的组,但不将其包括在结果中。 In this case it takes three digits at a time (from the end remember?) and leaves them out of the result for when replacing. 在这种情况下,一次需要输入三位数(从头到尾还记得吗?),并且在替换时将其排除在结果之外。
    • g : Match and replace globally, the whole string. g :全局匹配并替换整个字符串。
  • Replacing with $1, : This is how captured groups are referenced for replacing, in this case the wanted group is number 1 . 替换为$1, ,:这是引用捕获的组进行替换的方式,在这种情况下,所需组为1 Since the pattern will match every digit in the position 3n+1 (starting from the end or the dot) and catch it in the group number 1 ( (\\d) ), then replacing that catch with $1, will effectively add a comma after each capture. 由于该模式将匹配位置3n + 1中的每个数字(从末尾或点开始)并将其捕获到组号1(\\d) )中,然后用$1,替换该捕获$1,将在后面有效地添加一个逗号每次捕获。

Try it and please feedback. 试试看,请反馈。

Also if you haven't already you should (and SO has not provided me with a format to stress this enough) really really look into this site as suggested by Taplar 另外,如果您还没有这样做的话(那么SO并没有给我提供足够的格式来强调这一点),那么真的可以像Taplar所建议的那样浏览 该网站

Okay, I want to apologize to everyone who answered. 好的,我想向所有回答的人道歉。 I did some further tracing and found out the JSON call which was bringing in the amount did in fact have a comma in it, so it is just parsing that first digit. 我进行了一些进一步的跟踪,发现引入的JSON调用实际上确实包含逗号,因此它只是解析该第一位数字。 I was looking in the wrong place in the code when I thought there was no comma in there already. 当我认为代码中没有逗号时,我在代码中的错误位置进行了查找。 I do appreciate everyone's input and hope you won't think too bad of me for not catching that before this whole exercise. 我非常感谢大家的投入,并希望您不会因为在整个练习之前不了解我而感到不好。 If nothing else, at least I now know how that regex operates so I can make use of it in the future. 如果没有别的,至少我现在知道该正则表达式的运行方式,以便将来我可以使用它。 Now I just have to go about removing that comma. 现在,我只需要删除该逗号。

Have a great day! 祝你有美好的一天!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM