技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> JavaScript --> 正则表达式基础

正则表达式基础

浏览:4686次  出处信息

前段时间阅读Underscore源码的时候,踩了不少正则表达式的坑。正则表达式是一项非常实用的技能,可是每次遇到正则相关的问题,我都是回避(总以为正则表达式在网上搜搜就好了。同时,又觉得这玩意儿难,学习成本比较大)。看了司徒正美的一篇关于正则表达式的文章后,慢慢觉得正则并不是想象中那么难,关键是理解正则的核心思想后,多思考、多实践。本篇博文中的正则相关测试主要针对javascript

工具推荐:可视化正则工具

元字符

元字符是构建正则表达式的符号(用于连接字母和数字,创建高度描述性的文本模式)。常用的元字符有:( [ { \ ^ $ | ) ? * + .

如果要在正则中匹配这些元字符,需要加转义符\

// 匹配`?`var reg = /\?/;    reg.test('?123'); // true

来自MSDN的元字符的完整列表以及它们在正则表达式上下文中的行为:regex table

特殊字符

预定义的一些特殊字符:

  • \t:制表符

  • \v:垂直制表符

  • \n:换行符

  • \r:回车符

  • \f:换页符

  • \a:alert字符

  • \e:escape字符

  • \0:空字符

字符类

简单类

原则上正则的一个字符对应一个字符,我们可以用[]把它们括起来,让[]这个整体对应一个字符。如:

/js/.test('js');  // true    /[js]/.test('j'); // true// 结果返回一个匹配数组:["bat", "Cat", "fAt", "bat", "faT", "cat"]// 注意:如果正则中没有加入参数g,则返回第一个匹配console.log("a bat ,a Cat,a fAt bat ,a faT cat".match(/[bcf]at/gi));

负向类

[]中首字符设为^,表示匹配不能为括号里面的字符。如:

/[^abc]/.test("a"); // true   /[^abc]/.test("js"); //true

范围类

有时匹配的东西过多且类型又相同,全部输入太麻烦。可以利用[],同类字符之间加一个-即可。如:

/[a-z]/.test('x'); //true/[0-9]/.test('3'); //true

组合类

用[]匹配不同类型的单个字符。如:

/[a-z0-9]/.test('b'); // true   /[a-g0-5]/.test('z'); // false    /[^7-9]/.test("6"); // false

预定义类

预定义的一些常用字符类,本质上是[]的马甲:

  • .:匹配除了换行和回车之外的任意字符,相当于[^\n\r]

  • \d:匹配数字字符,相当于[0-9]

  • \D:匹配非数字字符,相当于[^0-9]

  • \s:匹配空白字符,相当于[ \t\n\x0B\f\r]

  • \S:匹配非空白字符,相当于[^ \t\n\x0B\f\r]

  • \w:匹配单词字符(所有的字母),相当于[a-zA-Z_0-9]

  • \W:匹配非单词字符,相当于[^a-zA-Z_0-9]

/\d/.test('3'); // true   /\S/.test(' '); // false    /\w/.test('_'); // true    /./.test('骏'); // true

量词

由于元字符与特殊字符或字符类或者它们的组合([])甚至它们的马甲(预定义类)都是一对一进行匹配。如果我们要匹配“正则表达式基础xxx”,最简单都要/..../。因此我们需要一个简单的操作,来处理这数量关系。

简单量词

  • ?:软性量词 出现零次或一次

  • *:软性量词 出现零次或多次(任意次)

  • +:软性量词 出现一次或多次(至少一次)

  • {n}:硬性量词 对应固定n次

  • {n,m}:软性量词 至少出现n次但不超过m次

  • {n,}:软性量词 至少出现n次(+的升级版)

/...../.test('正则表达式'); // true// /[\u4e00-\u9fa5]/用于匹配单个汉字    /[\u4e00-\u9fa5]{5}/.test('正则表达式');  // true    /\d+/.test('123456');  // true    /[js]{2}/.test('abc');  // false

贪婪量词、非贪婪量词、支配性量词

人都是贪婪的,正则也是如此。只要在合法的情况下,正则会尽量地多去匹配字符,这就叫做贪心模式。如果我们希望正则尽量少地匹配字符,只要在表示数字的符号后面加上一个?(即:问号加在量词的后边,则表示非贪婪模式)。组成如下的形式:{n,}?, *?, +?, ??, {m,n}?。上面两种模式都有个不断尝试的过程,而支配性量词却只尝试一次,如果不成功就算了(javascript不支持该模式!)

// 贪婪模式    alert(/c{1,}/.exec('cccccccccc')); // cccccccccc// 非贪婪模式    alert(/c{1,}?/.exec('cccccccccc')); // c

分组

到目前为止,我们只能一个字符的匹配。虽然量词的出现,能帮助我们处理一排密紧密相连的同类型字符,但这是不够的。下面该轮到小括号()出场了,中括号[]表示范围内选择,大括号{}表示重复次数,小括号允许我们重复多个字符。

//分组+量词    /(dog){2}/.test("dogdog"); // true//分组+范围    alert("baddad".match(/([bd]ad)*/)); //baddad,dad//分组+分组    alert("mon and dad".match(/(mon( and dad)?)/)); //mon and dad,mon and dad, and dad// ja是整个正则匹配的内容,j是第一个括号子正则表达式匹配的内容,a是第二个括号子正则表达式匹配的内容    alert(/(\w)(\w)/.exec('javascript')); // ja,j,a

反向引用

反向引用标识正则表达式中的匹配组捕获的子字符串。每个反向引用都由一个编号或名称来标识,并通过“\编号”表示法在正则规则中进行引用

var color = "#990000";  /#(\d+)/.test(color);  alert(RegExp.$1); // 990000// '\1'就是一个反向引用,它表示的是第一个括号内的子正则表达式匹配的内容  alert(/(dog)\1/.test("dogdog")); //truevar num = "1234 5678";  var newNum = num.replace(/(\d{4}) (\d{4})/,"$2 $1");  alert(newNum); // 5678 1234

候选

元字符|相当于正则表达式中的或,有一个候选项满足,就停止其它候选项匹配

var reg = /red|black|yellow/;    reg.test('red'); // true    reg.test('yellow'); // true    /^z|o.+/.exec('online'); // online    /^z|o.+/.exec('zhongguo'); // z    /(\d{6})|(abc*)/.test('abccc'); // true    /(\d{6})|(abc*)/.test('123456'); // true

非捕获性分组

并不是所有分组都能创建反向引用,有一种特别的分组称之为非捕获性分组,它不会创建反向引用,即可以避免保存括号内的匹配结果。反之,就是捕获性分组。要创建一个非捕获性分组,只要在分组的左括号的后面紧跟一个问号与冒号就行了((?:pattern))

// 捕获性分组   /^(b|c)\1/.exec('bbs.byr.cn'); // bb,b// 非捕获性分组    /^(?:b|c)\1/.exec('bbs.byr.cn'); // null    /^(?:b|c)/.exec('bbs.byr.cn'); // b// 移除所有标签,只留下innerTextvar html = "<p><a href='http://chenjunxyf.me/'>风影博客</a><em>chenjun</em></p>";    var text = html.replace(/<(?:.|\s)*?>/g,"");    console.log(text); //  风影博客chenjun

注意:javascript不存在命名分组

前瞻

正向前瞻

形式:(?=pattern)所谓正向前瞻,意思就是:要匹配的字符串,后面必须紧跟着pattern

   /chenjun(?=33)/.test('chenjun33'); // true    alert(/chenjun(?=33)/.exec('chenjun33')); // chenjun    /chenjun(?=33)/.test('chenjun233'); // false    alert(/chenjun(?=33)/.exec('chenjun233')); // null

负向前瞻

形式(?!pattern)和?=恰好相反,要求字符串的后面不能紧跟着某个pattern

   /chenjun(?!css)/.test('chenjuncss'); // false    alert(/chenjun(?!css)/.exec('chenjuncss')); // null    /chenjun(?!css)/.test('chenjun233'); // true    alert(/chenjun(?!css)/.exec('chenjun233')); // chenjun// 移除hr以外的所有标签,只留下innerTextvar html = "<p><a href='http://chenjunxyf.me/'>风影博客</a></p><hr/><p><em>chenjun</em></p>";    var text = html.replace(/<(?!hr)(?:.|\s)*?>/gi,"");    console.log(text); //  风影博客<hr/>chenjun

边界

要与字符串合用的特殊字符,前面基本都用到了!

  • ^:开头

  • $:结尾

  • \b:单词边界([a-zA-Z_0-9]之外的字符)

  • \B:非单词边界

// 利用正则实现首字母大写var a = 'chenjun';    String.prototype.capitalize = function(){      returnthis.replace(/^\w/, function(s){        return s.toUpperCase();      });    };    console.log(a.capitalize()); // Chenjun// 单词提取var str = "12w-eefd&efrew";    alert(str.match(/\b\w+\b/g)); //12w,eefd,efrew

思维导图

regex mind map

参考


建议继续学习:

  1. 统计最近用过的linux命令    (阅读:5021)
  2. grep 正则表达式选项要记得转义    (阅读:4913)
  3. 正则表达式的与或非    (阅读:4441)
  4. 学习Grep,Sed中的正则    (阅读:3767)
  5. URL正则表达式    (阅读:3351)
  6. 正则表达式简要入门    (阅读:3221)
  7. PHP 正则里面的两个重要技巧    (阅读:3169)
  8. 正则表达式简介及使用    (阅读:3064)
  9. 正则转义符汇总    (阅读:3072)
  10. 正则表达式傻瓜书 第二章:元字符    (阅读:3026)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1