理解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 相关文章推荐
jquery 经典动画菜单效果代码
Jan 26 Javascript
javascript 四则运算精度修正函数代码
May 31 Javascript
js动态删除div元素基本思路及实现代码
May 08 Javascript
javascript中this关键字详解
Dec 12 Javascript
laydate.js日期时间选择插件
Jan 04 Javascript
几种响应式文字详解
May 19 Javascript
React Native之prop-types进行属性确认详解
Dec 19 Javascript
JS获取当前时间的实例代码(昨天、今天、明天)
Nov 13 Javascript
微信小程序如何获取用户收货地址
Nov 27 Javascript
深入浅析nuxt.js基于ssh的vue通用框架
May 21 Javascript
vue中在vuex的actions中请求数据实例
Nov 08 Javascript
javascript将扁平的数据转为树形结构的高效率算法
Feb 27 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
用php将任何格式视频转为flv的代码
2009/09/03 PHP
phpStudy访问速度慢和启动失败的解决办法
2015/11/19 PHP
Zend Framework自定义Helper类相关注意事项总结
2016/03/14 PHP
PHP设计模式之建造者模式(Builder)原理与用法案例详解
2019/12/12 PHP
非常不错的一个javascript 类
2006/11/07 Javascript
JavaScript的Function详细
2006/11/14 Javascript
网页禁用右键实现代码(JavaScript代码)
2009/10/29 Javascript
js下用层来实现select的title提示属性
2010/02/23 Javascript
10个基于jQuery或JavaScript的WYSIWYG 编辑器整理
2010/05/06 Javascript
js中巧用cssText属性批量操作样式
2011/03/13 Javascript
基于jquery的滚动条滚动固定div(附演示下载)
2012/10/29 Javascript
js history对象简单实现返回和前进
2013/10/30 Javascript
JavaSacript中charCodeAt()方法的使用详解
2015/06/05 Javascript
php结合imgareaselect实现图片裁剪
2015/07/05 Javascript
移动端jQuery修正Web页面滑动时div问题的两则实例
2016/05/30 Javascript
jQuery+CSS实现简单切换菜单示例
2016/07/27 Javascript
使用jQuery.Qrcode插件在客户端动态生成二维码并添加自定义Logo
2016/09/01 Javascript
原生js实现购物车功能
2020/09/23 Javascript
[03:02]辉夜杯主赛事第二日 每日之星
2015/12/27 DOTA
python获取文件后缀名及批量更新目录下文件后缀名的方法
2014/11/11 Python
Python2.7读取PDF文件的方法示例
2017/07/13 Python
解决Mac下首次安装pycharm无project interpreter的问题
2018/10/29 Python
使用Python的toolz库开始函数式编程的方法
2018/11/15 Python
深入理解Django-Signals信号量
2019/02/19 Python
python飞机大战pygame碰撞检测实现方法分析
2019/12/17 Python
详解pandas绘制矩阵散点图(scatter_matrix)的方法
2020/04/23 Python
python字典与json转换的方法总结
2020/12/28 Python
pandas apply使用多列计算生成新的列实现示例
2021/02/24 Python
分享全球十款超强HTML5开发工具
2014/05/14 HTML / CSS
对象的序列化(serialization)类是面向流的,应如何将对象写入到随机存取文件中
2015/06/22 面试题
路政管理专业个人自荐信范文
2013/11/30 职场文书
小学阳光体育活动总结
2014/07/05 职场文书
个人四风问题对照检查材料思想汇报
2014/10/06 职场文书
依法行政工作汇报材料
2014/10/28 职场文书
2014年惩防体系建设工作总结
2014/12/01 职场文书
2016元旦晚会主持人开场白和结束语
2015/12/03 职场文书