理解千分符正则 /\B(?=(\d{3})+(?!\d))/g

2,895 阅读4分钟

说明

先看下工具方法

// `1234567.89` 转化成 `1,234,567.89`
function numberFormat(num) {
    return !isNaN(Number(num)) ? Number(num).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',') : '0.00';
}

一起来分析 /\B(?=(\d{3})+(?!\d))/g 上面方法中的灵魂正则

先简单看下 正则表达式-MDN

案例 '1234567.89'

拆分

\B 匹配一个非单词边界

可以匹配5种情况

  • 两个单词字符之间
'abc'.replace(/\B/g, ',') //匹配结果"a,b,c", 匹配到ab之间,bc之间,这两个字符之间的位置
  • 两个非单词字符之间
'a..b'.replace(/\B/g, ',') //匹配结果"a.,.b", 匹配到..之间,这两个非字符之间的位置
  • 空字符串
'a  b'.replace(/\B/g, ',') //ab之间有两个空格,匹配结果"a , b", 匹配到两个空格的位置
  • 字符串第一个字符为非“字”字符
    匹配的字符串的第一位不是‘字’ 比如字符串 '.abc',第一位为.能匹配到。
'.a'.replace(/\B/g, ',') //匹配结果",.a", 匹配到了.a 前面的. 并在前面加上了','
  • 字符串最后一个字符为非“字”字符
    同理匹配字符串的最后一位不是‘字’ 比如字符串 'abc.',最后一位为.能匹配到。
'a.'.replace(/\B/g, ',') //匹配结果"a.,", 匹配到了a. 最后一位. 并在后面加上了','

运行

// 能匹配到12之间,23之间等。因为7.8之间是有. 不满足以上5种情况
'1234567.89'.replace(/\B/g, ',')  // 运行结果 "1,2,3,4,5,6,7.8,9"

\d 匹配一个数字。等价于[0-9]。

'12'.replace(/\d/g, ',') // 匹配结果 ",," ,因为能匹配到数字1和2并替换成,

{3} 匹配了前面一个字符刚好出现了 3 次

{n} n 是一个正整数,匹配了前面一个字符刚好出现了 n

'123456'.replace(/\d{3}/g, ',') // 匹配结果 ",,",因为能匹配到123,456所以能替换成,

+ 匹配前面一个表达式 1 次或者多次。等价于 {1,}

// 匹配结果 ",",因为\d匹配数字+是多次,123就会被全部匹配到会替换成,。当然1234,12345等都是能匹配到替换成,
'123'.replace(/\d+/g, ',') 

(?!\d)

x(?!y) 仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找
(?!\d)就是后面不能跟着受罪

小小总结

(\d{3})+(?!\d) 表示匹配3位数字一次或者多次且满足于以上匹配的后面不能跟着数字

运行

'12345'.replace(/(\d{3})+(?!\d)/g, ',') // 匹配结果 "12,"
// 解析:
// (\d{3})+ 匹配的是3位数字一次或者多次,所以123能匹配上,(?!\d)表示不能跟数字,所以123又不满足
// 接着匹配 234 满足匹配3位数字一次或者多次,但是4后面是5跟着又是数字,所以234又不满足
// 接着匹配 345 满足匹配3位数字一次或者多次, 5后面跟着不是数字,能满足要求,345匹配上了替换成了','

?=

x(?=y) 匹配'x'仅仅当'x'后面跟着'y'.这种叫做先行断言

'abac'.replace(/a(?=b)/g, ',') // 匹配结果 ",bac"
// a后面必须跟着b 只有ab符合,ac不符合

大大总结

'1234567.89'.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
匹配到12,23等之间的位置,且满足于匹配的位置后面跟着3位数字一次或者多次且满足以上匹配的后面不能跟着数字

匹配过程解析:
首先匹配到 12 之间,满足 \B 的要求,后面跟着 234567 满足 ((\d{3})+3位数字出现一次或者多次,且7的后面跟着是.,不是跟着数字。完全满足在1 2之间加上,
接着匹配2 3之间,满足 \B 的要求,后面跟着 345 满足((\d{3})+3位数字出现一次或者多次,但是5的后面跟着是数字6,所以不满足匹配
同上一次匹配

'1234567.89'.replace(/\B(?=(\d{3})+(?!\d))/g, ',') // 匹配结果 "1,234,567.89"

升华

正则很重要,可以简化很多代码,经常在项目中看到别人写的正则,如果不理解可能这段代码对你来说就很难理解。所以正则多看多记。有事没事多瞄几眼吧。 正则表达式-MDN