理解javascript正则表达式


Posted in Javascript onMarch 08, 2016

了解RegExp类型:

ECMAScript通过RegExp类型来支持正则表达式。 var expression=/pattern/flags; 

正则表达式的模式(pattern)部分:

可以是任何简单或复杂的正则表达式,可以包含字符类,限定符,分组,向前查找,反向引用。 关于正则表达式中各种特殊字符(如 \,^,$,\w,\b 等)的含义可以参考 MDN 正则表达式-特殊字符 的整理。这里我们简单介绍一下向前查找和反向引用。

向前查找:正则表达式向前使用一些字符而不移动这些字符的位置,分为正向前预搜索也叫正向肯定查找( x(?=y) )与负向前预搜索也叫正向否定查找( x(?!y) )。
反向引用:标识字符串中可以提供的重复字符或字符串,可以使用捕获组反向引用匹配。带编号的反向引用 \number number是正则表达式中捕获组的序号位置。
1、表达式 \1~\9 解释为反向引用而不是八进制代码。 /\b(\w+)\s\1/.exec('s_ s_');//["s_ s_", "s_"]
2、如果多位表达式的第一个数字是8或者9(如 \80 或 \91 ),则该表达式将被解释为文本。 /\b(\w+)\s\80/.exec('s_ 800');//["s_ 80", "s_"]
3、对于编号为 \10 或更大值的表达式,如果存在与该编号对应的反向引用,则将该表达式视为反向引用。否则将这些表达式解释为八进制。

/(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)xx\10/.exec('12345678910xx10');//["12345678910xx10", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
/(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)xx\11/.exec('12345678910xx10');//null

4、如果捕获组嵌套捕获组,捕获组确定的顺序是内部从外到内,外部从左到右。来个代码体会一下。
/\b(\w+x(x))\s(\1)/.exec('s_xx s_xxSTOP');//["s_xx s_xx", "s_xx", "x", "s_xx"]
5、如果正则表达式包含对未定义的组成员的反向引用,则会发生分析错误,根据语言的不同正则表达式引擎将引发 ArgumentEXception 。对于javascript会返回null。/\b(\w+)\s\2/.exec('s_ 8');//null
反向引用实例代码:捕获组捕获到的内容不仅可以在正则表达式外部通过程序进行引用( RegExp.$n )也可以在正则表达式内部进行引用( \number ,这种引用方式就是反向引用)。

//表达连续三个相同的小写,{2}应用在\1身上
/([a-z])\1{2}/.exec('aaa');//["aaa", "a"]
复制代码
//一道有意思的正则问题
/(\w)((?=\1\1\1)(\1))/.exec('aa bbbb');//["bb", "b", "b", "b"]

/*这里捕获组有三个,$1为(\w)中的内容,$2为((?=\1\1\1)(\1))中的内容:
需注意(?=\1\1\1)并不是捕获组而是正则表达式的判断条件,x(?=y)表示匹配x仅仅当后面跟着y,判断条件并不是匹配结果的一部分。所以现在$2的内容为(\1)即‘b'。$3就是\1的内容。返回的匹配项
“bb”中的第一个'b'为"aa bbbb"中的第一个'b',第二个'b'为"aa bbbb"中的第二个'b'。*/

/(\w)(x(?=\1\1\1)(\1))/.exec('aa bxbbbcb');//["bxb", "b", "xb", "b"]
//这里$2的内容为(x(?=\1\1\1)(\1))中的内容即x(\1);

//其实上面两种模式可以简化成/(\w)(?=\1\1\1)(\1)/表示匹配\w仅当该\w后后面跟着三个\1,然后获取的匹配项为该\w且其后再紧跟着\1的字符串。同理/(\w)x(?=\1\1\1)(\1)/
复制代码
/(\w)((?=\1\1\1)(\2))/.exec('aa bbbbv');//["b", "b", "", ""]
/*捕获组$2为((?=\1\1\1)(\2))中的内容,由于此时还未执行完捕获组$2处的匹配,所以\2表示""。$3即为\2的内容还是""。所以这条匹配被解释为返回\w且其后紧跟3个该\w的字符串,返回\w+''就只返回'b'了。*/

正则表达式的标志位(flags)部分:

可以带有一个或多个标志,用以表明正则表达式的行为。

1、g:表示全局模式,模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止。 'cat mat bat'.replace(/.(?=at)/g,'A');//"Aat Aat Aat"
2、i:不区分大小写模式,在确定匹配项时忽略模式与字符串的大小写。 'cAt mat bAt'.replace(/a/gi,'B');//"cBt mBt bBt"
3、m:多行模式,在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。

var str='cat\nmat\nbat';
str.replace(/at/gm,'AB');
/*"cAB
mAB
bAB"*/

正则表达式中的元字符部分:

在模式中使用这些元字符时必须转义,如果想要匹配的字符串中包含这些字符,就需要对他们进行转义。

( [ { \ ^ $ | ) ? * + . ] }
//匹配"[bc]at"
/\[bc\]at/.exec("xx[bc]at");//["[bc]at"]

//匹配".at"
/\.at/.exec("xx.at");//[".at"]

创建正则表达式:

字面量形式:形如 var expression=/pattern/flags;
RegExp构造函数:两个参数(要匹配的字符串模式,可选的标志字符串),不能把正则表达式字面量传递给构造函数,虽然即使这样写了也不会报错。可以使用字面量定义的任何表达式都可以使用构造函数来定义。如下:

var p=/[bc]at/;
new RegExp('[bc]at');// /[bc]at/

1、当不传任何参数或参数一为空字符串时, new RegExp();// /(?:)/  或 new RegExp('');// /(?:)/ ,表示匹配 "" 但不记住匹配项( "" 其实就是 ":" 之后的空串,不记住x匹配项的规则为(?:x)),所以在匹配任何字符串时都返回 [""] 。所以由此可以猜想一下javascript正则引擎内部机制应该是默认匹配 "" 且不记住该匹配项,除非显式声明在 ":" 之后的需要匹配的字符串,加上 "(?:)" 显式声明不记住匹配项。
2、由于构造函数模式参数是字符串,所以某些情况下(是指那些已经转义过的字符)对字符进行双重转义(即在字面量形式的单重转义再来一层转义)。某些情况下当然也可以进行单重转移( new RegExp('\w');// /w/ )。注意'\'比较特殊,在字符串中也需要进行转义。

var p=/\\n/;//转义\,字符"\"在字符串中常需要被转义为"\\"
p.exec("\\nxx");//["\n"]

var p=new RegExp("\\\\n");// /\\n/ 如果想获得正则表达式字面量为/\\n/,需要在正则表达式中再来一层转义
p.exec('\\nxx');//["\n"] 注意被匹配的字符串'\nxx'中\n的\也被转义了

new RegExp('\\n').exec("\n");// 
["
"]
/*RegExp('\\n')返回/\n/,即意思匹配换行符*/

new RegExp('\n').exec("\n");//
["
"]
/*new RegExp('\n')返回
/
/ ,表示并没有进行转义,而是返回字面量
/
/,意思匹配换行符
*/

3、下面给出一些单重,双重转义模式的参考:第几次转义在表中已标出,单代表第一次转义,双代表在已经有的转义的基础上再进行的转义。

理解javascript正则表达式

RegExp的实例属性:

通过实例的属性可以获取有关模式的各种信息

 global :布尔值,表示是否设置了g标志。
 ignoreCase :布尔值,表示是否设置了i标志。
 multiline :布尔值,表示是否设置了m标志。
 lastIndex :整数,表示开始搜索下一个匹配项的字符位置,从0算起。前提是设置g标志时才会有用。
 source :正则表达式的字符串标志,按照字面量形式而非构造函数中的字符串模式返回字符串。

new RegExp('\\\\w');// /\\w/ 返回自面量形式正则表达式
new RegExp('\\\\w').source;// "\\w" 字符串

RegExp的实例方法:

理解javascript正则表达式

exec():该方法是专门为捕获组而设计的,参数为要匹配的字符串,返回包含第一个匹配项信息和可能有的捕获组的数组,若未匹配到返回 null 。(返回的虽然是 Array 的实例,但还包含两个额外的属性: index 表示匹配项在字符串中的位置, input 表示应用正则表达式的字符串)

var arr=new RegExp('\\\\(w)').exec('\\w');// ["\w", "w"]
arr;// ["\w", "w"]
arr.index;//0
arr.input;// "\w" 即exec()里的内容

exec() 和 match() 方法的区别:

1、对于 exec() 而言,即使在模式中设置了全局标志g,它每次也只返回一个匹配项;字符串的 match() 方法在设置g的时候可以返回全部匹配项而没有捕获组且返回的数组没有index和input属性。

2、对于exec()而言可以返回捕获组,但match()在没有全局g标志时才能返回捕获组,此时match()返回的数组有index和input属性。

//返回全局匹配项演示比较
var arr='ababcdab'.match(/ab/g);// ["ab", "ab", "ab"]
arr.index; // undefined
arr.input; // undefined
/ab/g.exec('ababcdab');// ["ab"]

//捕获组演示比较,match()方法和有无设置全局g标志有关
'ababcdab'.match(/a(b)/g);// ["ab", "ab", "ab"]
var arr='ababcdab'.match(/a(b)/);// ["ab", "b"]
arr.index;// 0
arr.input;// 'ababcdab'
/a(b)/g.exec('ababcdab');// ["ab", "b"]

3、所以在选择使用方法的时候要先考虑好侧重该方法的哪方面功能,在不设置全局标志g的情况下,在同一个字符串上多次调用exec()则总是返回第一个匹配项的信息,而在设置全局标志的情况下,每次调用exec()则都会在字符串中沿着上次查找的位置往后继续查找新的匹配项。

//未设全局,每次从头开始查找
var p=/a/;
var str='ababa';
var a=p.exec(str);// ["a"];
var b=p.exec(str);// ["a"];
a==b;// false
a.index==b.index;// true

//设置全局,沿着上次位置继续查找新匹配
var p=/a/g;
var str='ababa';
var a=p.exec(str);// ["a"]
a.index;// 0
var b=p.exec(str);// ["a"]
b.index;// 2

test():接收字符串参数,在模式与字符串参数匹配情况下返回 true ,否则返回 false 。常被用在 if() 中当判断条件。

var text="000-000-000";
var p=/((\d{3})-)\1*\2/; if(p.test(text)){
 console.log('匹配成功');
}

RegExp 实例继承 Object 的 toLocaleString() 和 toString() 方法都会返回正则表达式的字面量形式的字符串,与如何创建正则表达式的方式无关。 valueOf() 则返回正则表达式字面量本身。

var p=/\[new\]bi/;
p.toLocaleString();// "/\[new\]bi/"
p.toString();// "/\[new\]bi/"
p.valueOf();// /\[new\]bi/

var p=new RegExp('\\[new\\]bi');
p.toLocaleString();// "/\[new\]bi/"
p.toString();// "/\[new\]bi/"
p.valueOf();// /\[new\]bi/

RegExp的构造函数属性:

构造函数本身包含一些属性(静态属性),这些属性适用于作用域中的所有表达式,并且基于所执行的最近一次正则表达式操作而变化。有长属性名(如下代码)和短属性名(即$前缀形式,由于这些符号大多不是有效的ECMAScript标识符,所以不能直接在 RegExp 构造函数上以 "." 的方式访问,而要通过方括号语法来访问)两种方式访问这些属性

/(.)hort/g.exec('this is a short day');// ["short", "s"]

//最近一次要匹配的字符串
RegExp.input;// "this is a short day" 或RegExp["$_"]访问;

//最近一次的匹配项
RegExp.lastMatch;// "short" 或RegExp["$&"]访问;

//在最近一次要匹配的字符串中的最近一次匹配项之前的文本 
RegExp.leftContext;// "this is a " 或RegExp["$`"]访问;

//在最近一次要匹配的字符串中的最近一次匹配项之后的文本 
RegExp.rightContext;// " day" 或RegExp["$'"]访问;

//最近一次(最后一次)匹配的捕获组
RegExp.lastParen;// "s" 或RegExp["$+"]访问;

捕获组访问属性:还有9个用于存储捕获组的构造函数属性,访问语法是 RegExp.$n ,其中n取值1~9,用于获取第n个匹配的捕获组。在调用 exec() , test() 或 match() 等正则系列方法时这些属性会被自动填充。

var text="this is a short summer";
var pattern =/(..)or(.)/g;
if(pattern.test(text)){
 console.log(RegExp.$1); // sh
 console.log(RegExp.$2); // t 
}

模式的局限性:

缺少一些高级正则表达式的特性,如不支持向后查找,命名的捕获组(形如 \k<name> 引用之前名为 name 的捕获组的字符串)等。

推荐专题 《javascript正则表达式使用说明》

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
javascript 回到顶部效果的实现代码
Feb 17 Javascript
js写出遮罩层登陆框和对联广告并自动跟随滚动条滚动
Apr 29 Javascript
checkbox选中与未选中判断示例
Aug 04 Javascript
jQuery中triggerHandler()方法用法实例
Jan 19 Javascript
jquery实现在光标位置插入内容的方法
Feb 05 Javascript
javascript无刷新评论实现方法
May 13 Javascript
关于JS 预解释的相关理解
Jun 28 Javascript
基于vue实现swipe分页组件实例
May 25 Javascript
vue init webpack myproject构建项目 ip不能访问的解决方法
Mar 20 Javascript
js尾调用优化的实现
May 23 Javascript
详解vue-cli3开发Chrome插件实践
May 29 Javascript
vue实现固定位置显示功能
May 30 Javascript
JavaScript实现带播放列表的音乐播放器实例分享
Mar 07 #Javascript
详解JavaScript数组和字符串中去除重复值的方法
Mar 07 #Javascript
JavaScript实现字符串与日期的互相转换及日期的格式化
Mar 07 #Javascript
JavaScript中将数组进行合并的基本方法讲解
Mar 07 #Javascript
Bootstrap每天必学之日期控制
Mar 07 #Javascript
JavaScript过滤字符串中的中文与空格方法汇总
Mar 07 #Javascript
jquery+json实现分页效果
Mar 07 #Javascript
You might like
利用XMLHTTP传递参数在另一页面执行并刷新本页
2006/10/26 Javascript
JS类中定义原型方法的两种实现的区别
2007/03/08 Javascript
高性能WEB开发 flush让页面分块,逐步呈现 flush让页面分块,逐步呈现
2010/06/19 Javascript
妙用Jquery的val()方法
2012/06/27 Javascript
js动态拼接正则表达式的两种方法
2014/03/04 Javascript
JavaScript中按位“异或”运算符使用介绍
2014/03/14 Javascript
js实现带有介绍的Select列表菜单实例
2015/08/18 Javascript
CSS javascript 结合实现悬浮固定菜单效果
2015/08/23 Javascript
js中遍历对象的属性和值的方法
2016/07/27 Javascript
简单分析javascript中的函数
2016/09/10 Javascript
js设置文字颜色的方法示例
2016/12/30 Javascript
Vue实现选择城市功能
2017/05/27 Javascript
微信小程序实现表单校验功能
2020/03/30 Javascript
微信小程序自定义带价格显示日历效果
2018/12/29 Javascript
[51:14]LGD vs VP 2018国际邀请赛淘汰赛BO3 第一场 8.21
2018/08/22 DOTA
[55:44]完美世界DOTA2联赛决赛 FTD vs Phoenix 第二场 11.08
2020/11/11 DOTA
import的本质解析
2017/10/30 Python
python中的for循环
2018/09/28 Python
Python3转换html到pdf的不同解决方案
2019/03/11 Python
浅谈PyQt5 的帮助文档查找方法,可以查看每个类的方法
2019/06/25 Python
Python3多线程版TCP端口扫描器
2019/08/31 Python
简单了解python中的f.b.u.r函数
2019/11/02 Python
Python 调用有道翻译接口实现翻译
2020/03/02 Python
Django 5种类型Session使用方法解析
2020/04/29 Python
浅析Python 简单工厂模式和工厂方法模式的优缺点
2020/07/13 Python
Python操作MySQL数据库的示例代码
2020/07/13 Python
纯HTML5+CSS3制作图片旋转
2016/01/12 HTML / CSS
HTML 5.1来了 9月份正式发布 更新内容预览
2016/04/26 HTML / CSS
德国团购网站:Groupon德国
2018/03/13 全球购物
园长自我鉴定
2013/10/06 职场文书
数控专业自荐书范文
2014/03/16 职场文书
党的群众教育实践活动实施方案
2014/06/12 职场文书
四风批评与自我批评发言稿
2014/10/14 职场文书
外贸业务员岗位职责
2015/02/13 职场文书
2015年妇幼保健工作总结
2015/05/19 职场文书
python游戏开发之pygame实现接球小游戏
2022/04/22 Python