每周获取最新的 Wordpress 资源

JavaScript 正则表达式

什么是正则表达式?即描述字符串规则的表达式,表达对字符串的一种过滤逻辑,正则表达式的主要作用就是为了匹配和获取。

那么 Javascript 中正则表达式的语法是什么样的?总的来讲就是规则加属性:

  • 直接量:/pattern/flags
  • 对象构造方式:new RegExp(pattern, flags)

上面的 pattern 是一些有规则的字符集,flags 即标志位,通常有这几个:g( global 全局匹配),i(ignoreCase 忽略大小写),m(multiline)多行

另外,在学习过程中,我们可以通过 regexObj.test(str) 测试正则表达式与指定字符串是否匹配,如:

/13666668888/.test("13666688888"); //false
/13666668888/.test("13666668888"); //true
/13666668888/.test("sy13666668888sd"); //false

开始之前,我们先看一眼,最常用的正则的基本语法规则如下表格:

规则 描述 规则 描述
[xyz] 一个字符集,匹配任意一个包含的字符 [^xyz] 一个否定字符集,匹配任何未包含的字符
\w 匹配字母或数字或者下划线的字符 \W 匹配不是字母,数字,下划线的字符
\s 匹配任意空白符 \S 匹配不是空白符的字符
\d 匹配数字 \D 匹配非数字的字符
\b 匹配单词的开始或结束的位置 \B 匹配不是单词开头或结束的位置
$ 匹配字符串的开始 ^ 匹配字符串的结束

正则表达式中的锚点

匹配一个位置

  • $ 匹配字符串的开始
  • ^ 匹配字符串的结束
  • \b 匹配单词的开始或结束的位置

组合起来再来重写之前那个验证手机号的正则表达式,检测效果就会更准确点:

/^13666668888$/.test("sy13666668888sd"); //false

字符类

匹配一类字符中的一个

  • [abc]:a或b或c
  • [0-9]:一个数字,[^0-9]:非数字的一个字符
  • [a-z]:一个字母
  • . :任一字符(换行除外)
/[^0-9]/.test("abc"); //true

再次重写验证手机号的正则表达式,检测效果又会更准确点:

/^1[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$/.test("23666668888"); //false

元字符

具有特殊意义的字符

  • ^$\b
  • \d[0-9] 是等价的,\D[^\d] 是等价的
  • \s:空白符,\S[^\s] 非空白符
  • \w[A-Za-z0-9]\W[^\w]

再次重写验证手机号的正则表达式,这次会更简洁了:

/^1\d\d\d\d\d\d\d\d\d\d$/.test("23666668888"); //false

但是依旧违背了我们程序中 DRY 编程原则,就是 Don't repeat yourself!

量词

出现的次数

  • {m,n}:m 到 n 次
  • {m,}:m 到任意次
  • {m}:m 次
  • *{0,},0到任意次
  • ?{0,1},0或1次
  • +{1,},1到任意次,也就是至少出现过一次
/\d*/.test("abc"); //true,0-9出现0次,没毛病
/\d+/.test("abc"); //false,0-9至少要出现1次

/https?:/.test("https://wordpresshi.com"); //true
/https?:/.test("httpss://wordpresshi.com"); //false,https 出现一次后应该紧跟 :

最后我们在重写下验证手机号的正则表达式:

/^1\d{10}$/.test("13666668888"); //true

转义符

什么时候需要转义符?

需要匹配的字符是元字符,如 /^http:\/\//(以http://开头),/@163\.com$/(以@163.com结尾)

多选分支

“或”的意思

/thi(c|n)k/ === /thi[cn]k/ 两者其实是等价的

用来匹配图片文件可以这么写:

/\.(png|jpg|jpeg|gif)$/

用来验证是否为某几个类型的邮箱:

/(.+)@(163|126|188)\.com$/

分组与捕获

保存匹配到的字符串,日后再用,怎么做?

  • ():捕获型分组,如 /(.+)@(163|126|188)\.com$/
  • (?:):非捕获型分组,如 /(.+)@(?:163|126|188)\.com$/

对于捕获型分组该如何引用呢?可以通过:$1$2 等等来引用,比如:

var reg = /I love (coding|girl)/.exec('I love coding.');
// 然后就可以这样引用捕获到的字符串 "coding"
RegExp.$1

还有反向引用,比如:

// 用 1 来表示第一个捕获的 div
var reg = /<(div)>.*<\/\1>/;

贪婪模式和惰性模式

正则表达式中,量词的贪婪模式与惰性模式有什么区别?

其实上面介绍的量词都是贪婪模式(最常用的模式),量词还有个较常用的模式是惰性模式。属于贪婪模式的量词,包括: {m,n}{m,}?*+,在贪婪模式的量词后加上?,即变成惰性模式,包括:{m,n}?{m,}???*?+?

举个例子:

var str = '<span>Hello</span><span>world</span>'
var reg1 = /<span>.+<\/span>/;
var reg2 = /<span>.+?<\/span>/;

reg1.exec(str); // 会匹配到 '<span>Hello</span><span>world</span>'
reg2.exec(str); // 会匹配到 '<span>Hello</span>'

总结一下:

  • 贪婪模式:在匹配成功的前提下,尽可能多的去匹配
  • 惰性模式:在匹配成功的前提下,尽可能少的去匹配

正向前瞻和负向前瞻

先看看语法:

  • 正向前瞻(look ahead positive assert):?=
  • 负向前瞻(look ahead negative assert):?!

以例子说明,第一种情况,正向前瞻和负向前瞻匹配字符:

var str = 'Ted love coding';
// 正向前瞻,匹配后面跟着 ' love coding' 的 Ted
var reg1 = /Ted(?= love coding)/
// 负向前瞻,匹配后面没有跟着 ' love girl' 的 Ted
var reg2 = /Ted(?! love girl)/

reg1.exec(str); // 会匹配到 'I'
reg2.exec(str); // 会匹配到 'I'

第二种情况,正向前瞻和负向前瞻匹配位置:

var str = 'Ted love girl';
var reg1 = /(?= love girl)/
var reg2 = /(?! love coding)/

正则表达式相关方法

除了我们上面一直使用的 test() 方法,还有三个常用正则表达式相关的方法。

match 方法

str.match(regexp) 获取匹配的字符串

var url = 'http://blog.163.com/album?id=1#comment';
var reg = /^(https?:)\/\/([^\/]+)(\/[^\?]*)?(\?[^#]*)?(#.*)?$/;
// var reg = /(https?:)\/\/([^\/]+)([^\?]*)([^#]*)(.*)/;
var arr = url.match(reg);
console.log(arr);
var protocol = arr[1];
var host = arr[2];
var pathname = arr[3];
var search = arr[4];
var hash = arr[5];

replace 方法

str.replace(regexp/substr,replacement) 替换一个子串

var str = 'The price of tomato is 5.';
str.replace(/(\d+)/, '$1.00');

但是这个正则只匹配了1次就停下来了,如果有多个价格,就无法替换了,比如:

var str = 'The price of tomato is 5. The price of apple is 10.';
str.replace(/(\d+)/, '$1.00');
// 此时会输出
// The price of tomato is 5.00. The price of apple is 10.

要想全局匹配并且替换,需要在正则表达式最外层加 g,如:

str.replace(/(\d+)/g, '$1.00');

再看个实例,转义HTML:

<div id="container"></div>
<script>
  var container = document.getElementById('container');

  var html = '<label>网址:</label><input placeholder="以http://起始">';
  html = html.replace(/[<>]/g, function(m0){
    switch(m0){
      case '<':
        return '&lt;';
      case '>':
        return '&gt;';
    }
  });
  console.log(html);
  container.innerHTML = html;
</script>

exec 方法

regexpObj.exec(str) 更强大的检索

  • 更详尽的结果:index
  • 过程的状态:lastIndex
var reg = /(.)(\d+)/g;
var scores = 'Tom $88, Nicholas ¥100, jack £38.';
var result;
while(result = reg.exec(scores)){
  console.log(result);
  console.log(reg.lastIndex);
  // reg.lastIndex += 10;
}

除此之外,正则相关的方法,还有 split()search(),具体可以看 MDN 文档。

总结和自测

最最最常用的正则表达式相关的知识点都涵盖了,当然正则最关键的还是要多练习。

考虑下面的一个面试题,看看能不能读懂。看懂的话,正则基础就还不错啦!

var reg = /(?=(?!\\b)(\\d{3})+$)/g;

最后的最后,分享一些正则表达式可视化在线工具,帮助你更好的理解正则表达式:

You May Also Like

About the Author: ted

发表评论

电子邮件地址不会被公开。 必填项已用*标注