JS 正则中环视(断言)应用 -- 数字千分符

Posted liyan.web

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS 正则中环视(断言)应用 -- 数字千分符相关的知识,希望对你有一定的参考价值。

介绍一下顺序环视 (?=...) 和逆序环视 (?<=...) 
方便不想看长文的人,如果在支持 ES2018 的环境中整数可以这样使用:

String(12345678).replace(/(?<=d)(?=(d{3})+)/g, ‘,‘) // "12,345,678"

 

其中最关键的是肯定顺序环视(?=...),也叫零宽度正预测先行断言
添加千分符麻烦的地方在于只有在从右到左 3 的倍数的位数和前面的数字中间需要添加逗号
而正则是从左到右匹配的,这时候就需要用到顺序肯定环视。
环视不占用字符,能匹配到符合要求的位置
比如,`/Java(?=Script)/` 只会匹配后面有 Script 的 Java 字符

‘Java or javascript‘.replace(/Java(?=Script)/, ‘Type‘); // "Java or TypeScript"

 

我们知道匹配连续的 3 个数字的方法是 /d{3}/ 3 的倍数的位数的数字就是 /(d{3})+/
再结合顺序肯定环视,我们就能匹配到后面有 3 的倍数的位数前面的位置 /(?=(d{3})+)/

这样我们就成功一半了,下面的问题是 `123456` 这样的 6 位数,前面不需要加分隔符。
所以我们还需要匹配前面有数字的位置,这就需要肯定逆序环视 /(?<=d)/
逆序环视和顺序环视相反,是指定模式后面的位置比如:

‘Adding subscripts using Javascript‘.replace(/(?<=Java)script/, ‘Script‘); // "Adding subscripts using JavaScript"

 

上面两个加起来就可以匹配到前面有数字,且后面有 3 的倍数的位置,但如果你这样子写:

String(12345678).replace(/(?<=d)(?=(d{3})+)/g, ‘,‘); // "1,2,3,4,5,678"

会发现和预期不同,右边三位数字前面的每个数字后都加了逗号。
我们可以使用单词分隔符 `` 来解决这个问题

String(12345678).replace(/(?<=d)(?=(d{3})+)/g, ‘,‘) // "12,345,678"

 

如果你是在支持 ES2018 环境下运行那到这里就可以了,但目前很多浏览器还不支持逆序环视。好在我们可以稍微变通,不使用逆序环视来解决

String(12345678).replace(/(d{1,3})(?=(d{3})+)/g, ‘$1,‘) // "12,345,678"


为了方便可以添加一个函数

function formatNumber(number) {
    if (typeof number !== ‘number‘) {
        throw new Error(‘formatNumber parameter must be number‘);
    }
    if (Number.isNaN(number)) {
        return ‘0‘;
    }
    let result;
    const [integerNum, decimalNum] = String(number).split(‘.‘);
    return integerNum.replace(/(d)(?=(d{3})+)/g, ‘$1,‘) + (decimalNum ? `.${decimalNum}` : ‘‘);
}

 

如果想用国内的习惯,按万位划分,把 3 改 4 即可

以上是关于JS 正则中环视(断言)应用 -- 数字千分符的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式高阶技巧之环视(使用python实现)

如何使用 DFA 正则表达式匹配器实现正则表达式断言/环视(即 \b 样式字边界)

正则(高级)(转)

正则表达式——断言补充

添加数字千分位逗号正则分析

环视-顺序肯定环视-零宽断言-正向预查-反向预查