正则表达式从右到左阅读

时间:2013-05-30 12:10:02

标签: javascript regex

我正在寻找一个简短的代码,可以将逗号放入一组数字中,直到我来到this site

代码:

function addCommas(nStr)
{
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}  

工作真的很棒。有这个例子的数字集:

addCommas('83475934.89');  

将返回"83,475,934.89",但是当我阅读代码时,我希望它返回8,3,4,7,5,934.89,但此网站会解释

  

\d+\d{3}组合将匹配一组3个数字,前面跟着任意数量的数字。这使得搜索从右到左进行替换。

我很困惑。 这段代码如何从右到左阅读?另外,$1$2的含义是什么?

6 个答案:

答案 0 :(得分:14)

实际从右向左阅读。真正发生的是它重复应用(\d+)(\d{3})模式(通过while循环)并替换,直到它不再匹配模式。换句话说:

迭代1:

x1 = 83475934.89
x1.replace((\d+)(\d{3}), '$1' + ',' + '$2');
x1 = 83475,934.89

迭代2:

x1 = 83475,934.89
x1.replace((\d+)(\d{3}), '$1' + ',' + '$2');
x1 = 83,475,934.89

迭代3:

x1 = 83,475,934.89
x1.replace((\d+)(\d{3}), '$1' + ',' + '$2');
// no match; end loop

修改

  

另外,$ 1和$ 2是什么意思?

这些分别是对匹配组(\d+)(\d{3})的反向引用。

这是学习正则表达式实际工作方式的绝佳参考:
http://www.regular-expressions.info/quickstart.html

答案 1 :(得分:7)

它从右到左匹配,因为它使用贪婪模式匹配。这意味着它首先找到所有数字(\ d +),然后尝试找到\ d {3}。例如,在数字2421567.56中,它将首先匹配数字直到'。' - 2431567 - 然后向后工作以匹配正则表达式的下一部分中的下三个数字(567)。它在一个循环中执行此操作,在$ 1和$ 2变量之间添加逗号。

$表示在正则表达式中用括号形成的匹配组,例如(\ d +)= $ 1和(\ d {3})= $ 2。这样,它可以轻松地在它们之间添加字符。

在下一次迭代中,贪婪匹配在新创建的逗号处停止,并且继续直到它不匹配> 3位数。

答案 2 :(得分:3)

这个解释在同一页面上进一步说明

  

代码说明:代码开始将字符串分成两部分   如果有小数,则部分( nStr nStrEnd )。正则表达式   用于 nStr 以添加逗号。然后添加 nStrEnd 。如果   字符串没有 nStrEnd 暂时删除,然后是常规   表达式将 10.0004 格式化为 10.0,004

     

正则表达式解释 \ d + \ d {3} 结合使用   匹配一组3个数字,前面是任意数量的数字。这个   欺骗搜索从右到左替换。

$1$2是正则表达式中捕获的组匹配。您可以在Regex Tutorial上阅读有关此主题的更多信息。

答案 3 :(得分:2)

代码从右到左阅读,它的作用是搜索最大的一行数字(\d+),然后是3位(\d{3})。 $ 1和$ 2分别是最大的数字行和3位数。因此它将逗号放在它们之间,通过重复此过程,它可以通过这种方式解析它。

答案 4 :(得分:2)

我写了一个正则表达式,它在一次传递中做同样的事情:

/(?!\b)(\d{3}(?=(\d{3})*\b))/g

尝试使用例如开头的不同数字:



var num = '1234567890123456';

for(var i = 1; i <= num.length; i++)
{
  console.log(num.slice(0, -i).replace(/(?!\b)(\d{3}(?=(\d{3})*\b))/g, ',$1'));
}
&#13;
&#13;
&#13;

我试着在这里分解它:

暂时忽略这一点 - 我会回过头来看。

  

<强>(?!\ b)中(\ d {3}(?=(\ d {3})* \ b))的


它仍然从左到右读取,试图捕获3位数的块。这是捕获组。

  

(?!\ b)中的(\ d {3} (?=(\ d {3})* \ b)中的


但是,在捕获组内部,它使用前瞻。

  

(?!\ B)(\ d {3}的(?= (\ d {3})* \ B'B>))


前瞻查找锚定到数字末尾的3位数的任意倍数 - 终止边界。这会将捕获与数字的右端3 的倍数对齐。这意味着它也可以使用十进制数字(除非它们超过3个小数位,在这种情况下它也会在其中加入逗号。它不是完美的。)

  

(?!\ B)(\ d {3}(?= (\ d {3})* \ B'/ B>))


我遇到的问题是JavaScript不支持原子查找,因此,当数字有3位数的倍数时,它匹配前3位数字并在数字的最开头加上逗号。
你不能在3位数匹配之前匹配一个字符而不会丢掉重复,所以我不得不使用与字边界相匹配的负向前瞻。它与^一开始就相反。

  

(?!\ b)中(\ d {3}(?=(\ d {3})* $))


从本质上讲,它可以防止表达式从字符串的开头匹配 哪个会不好。

答案 5 :(得分:0)

只是反转字符串

function addCommas(num_as_string) {
    // convert into string
    num_as_string+='';
    if (num_as_string === "") {
        return num_as_string;
    }
    /* add more test here*/
    // split the integer part and decimal part
    let [integer_part, decimal_part] = num_as_string.split('.');
    if (decimal_part === undefined) {
        decimal_part = '';
    } else {
        decimal_part = '.' + decimal_part;
    }

    return integer_part.split('').reverse().join('').match(/\d\d?\d?/g).reverse().map(v => v.split('').reverse().join('')).join(',') + decimal_part;
}

输出:

addCommas('83475934.89')
"83,475,934.89"

addCommas(83475934.89)
"83,475,934.89"

addCommas(83475934)
"83,475,934"