踩坑侠:Js正则(零宽断言)解决腾讯面试题

1,978 阅读4分钟

Hi,大家好,我是踩坑侠! 今天给大家带来关于正则匹配的一个面试题的分享。如果大家觉得有帮助,记得点个赞呀!




前言:

腾讯曾经出过这样一道面试题:
如何给一串数字用千分制表示?比如9999999999变成9,999,999,999

大家可能会说:用操作字符串的办法做,变成字符串,先除以3,看有几对,然后再加逗号…………(省略无数个步骤,这实在是太麻烦啦。。)
也有小伙伴说,可以用(123456789.123).toLocaleString('en-US')。没错,但是本文的思想是想要探讨如何用正则来解答,旨在熟悉正则。(tips:.toLocaleString('en-US')不能对小数点后超过3位的数字进行,分割)

那么,让我们我们先为解答这道题来了解一些相关的概念吧!

1. 零宽断言

写法 名称 含义
exp1(?=exp2) 正向前瞻 查找exp2前面的exp1
(?<=exp2)exp1 负向前瞻 查找exp2后面的exp1
exp1(?!exp2) 正向后瞻 查找后面不是exp2的exp1
(?<!exp2)exp1 负向后瞻 查找前面不是exp2的exp1

Tips: 关于零宽断言的叫法有很多种。本文提到的这几种网上都要涉及到。 下面的正向先行断言就是正向前瞻,是我们解题要用到的。

为了更方便大家理解,举一个例子:

  1. 正向先行断言(正向零宽断言)
'中国人'.replace(/中(?=国人)/, 'rr')
输出:rr国人
  1. 反向先行断言
'中国人'.replace(/(?<=中国)人/, 'rr')
输出:中国rr
  1. 负正向先行断言(负向零宽断言)
'中国人中'.replace(/中(?!国人)/, 'rr')
输出:"中国人rr"
  1. 负反向先行断言
'中国人中'.replace(/中(?<!国人)/, 'rr')
输出:"rr国人中"

"abZWab863ab88".replace(/(?<![A-Z])ab/g, "")
输出:"ZWab86388"



2.解题思路:

关于腾讯的这道面试题:
如何给一串数字用千分制表示?比如9999999999变成9,999,999,999。要想解答这道题,需要了解以下几个知识点:

  1. replace与正则约定的特殊标记符$
  2. 分组语法

1. replace()方法与正则约定的特殊标记符$

写法 含义
$i (i:1-99),表示从左到右正则子表达式所匹配的文本
$& 表示与正则表达式匹配的全文本
$` `:切换技能键。表示匹配字符串左边的文本
? 表示$转移

2. 分组语法:

写法 含义
捕获
(exp) 匹配exp,并捕获到自动命名到组里
(?<name>exp) 匹配exp,并捕获文本到名称为name到组里
(?:exp) 匹配exp,不捕获匹配的文本
位置指定
exp1(?=exp2) 查找exp2前面的exp1
(?<=exp2)exp1 查找exp2后面的exp1
exp1(?!exp2) 查找后面不是exp2的exp1
(?<!exp2)exp1 查找前面不是exp2的exp1
注释
(?#comment) 这种类型的组不对正则表达式对处理产生任何影响,只是为了提供让人阅读注释

解析:

  1. 这里我们采用的是 epx1(?=epx2)正向前瞻
  2. epx1对应的是正则符号是\d
    因为第一个逗号之前的数字范围在1-3个之间,所以限定范围 \d{1-3}
  3. 然后,exp2对应的是需要限定每3位数字添加一个,
    所以epx2的正则表达应该是:(\d{3}+$)(+:出现1次或多次;$:限定以xxx结尾)
  4. 最后,replace()方法第二个参数:使用$&符号。
    $&,表示捕获与正则表达式匹配的全文本并置换为,
  5. 这样写来下就是'99999999999'.replace(/\d{1,3}(?=(\d{3})+$)/g, '$&,')

接下来:做一道扩展题: 有小数点的'99999999999.02'做千分之转换,要怎样写呢?

写法一

'99999999999.02'.replace(/\d{1,3}(?=(\d{3})+(?:\.\d+)?$)/g, '$&,')
输出:"99,999,999,999.02"

'99999999999.33333333'.replace(/\d{1,3}(?=(\d{3})+(?:\.\d+)?$)/g, '$&,')
输出:"99,999,999,999.33,333,333"

写法二

正则表达式的写法大多数的时候都不止一种。 千分之表达的另外的一种写法是:

"123456789.12123".replace(/(?!^)(?=(\d{3})+(?:\.\d+)?$)/g, ',')

Tips: 这种写法与之前的写法最大的区别就是:将exp1的部分改为限定字符串的开头不可以添加,




结尾: 谢谢大家阅读,如果觉得对你有帮助,请给作者一点小小的鼓励, 点个赞或者收藏吧。 有需要沟通的请联系我: 微信( wx9456d) 邮箱( allan_liu986@163.com )