正则表达式,也称规则表达式,常用其来完成对字符串的校验和过滤。因为正则表达式的灵活性、逻辑性和功能性都很是强大,并且 能够利用很简单的方式完成对复杂字符串的控制,因此不少程序语言都支持正则表达式。在JavaScript
中正则表示也很是强大和实用。javascript
正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符串的模板,经常用做按照“给定模式”匹配文本的工具。好比,正则表达式给出一个Email地址的模式,而后用它来肯定一个字符串是否为Email地址。JavaScript的正则表达式体系是参照Perl 5创建的。html
新建正则表达式有两种方法。一种是使用字面量,以斜杠表示开始和结束。java
// 字面量形式 var telRegex1 = /^1[3|5|7|8]\d{9}$/; // 构造函数形式 var telRegex2 = new RegExp('^1[3|5|7|8]\\d{9}$');
以上都是建立了一个内容为^1[3|5|7|8]\d{9}$
的正则表达式,其表示对一个手机号码的校验。必须以1开始,第二位为3/5/7/8,以后为9位数字。es6
这两种写法——字面量和构造函数——在运行时有一个细微的区别。采用字面量的写法,正则对象在代码载入时(即编译时)生成;采用构造函数的方法,正则对象在代码运行时生成。考虑到书写的便利和直观,实际应用中,基本上都采用字面量的写法。web
有一点须要注意,使用构造函数建立正则表达式时,传入的参数是字符串形式的,在字符串内部,\
自己也是一个转义符,所以须要再使用一个\
来对其进行正则表达式的转义。上面第二个示例中,\\d
才能表明任意数字。正则表达式
关于正则表达式中,各类符号的含义,以及使用方法,请看后面的介绍:express
一些经常使用的元字符以下:数组
.
匹配除换行符以外的任意字符jsp
\w
匹配字母或数字或下划线或汉字函数
\s
匹配任意的空白符
\d
匹配数字
\b
匹配单词的开始或结束
^
匹配字符串的开始处
$
匹配字符串的结束处。
*
匹配前面的子表达式任意次。
?
匹配前面子表达式0次或一次,等价于{0, 1}
。
+
匹配以前子表达式一次到屡次,等价于{1, }
。
{n}
匹配以前的子表达式n次。
{m,n}
匹配以前的子表达式最少m次,最多n次。
{n, }
匹配以前的子表达式至少n次。
[xyz]
字符集合,表示其中任意一个字符。表示范围可用-
连接,例如[a-z]
表示a-z之间的任意一个字母。还能够这样书写[A-Za-z0-9]
。
[^xyz]
字符便可,表示非其中任意一个字符。表示范围可用-
连接,例如[^a-z]
表示非 a-z之间的任意一个字母。
|
表示或(or)
关系,例如 com|cn
,表示匹配com或者cn。
()
用于分组,其分组中的内容可已经过$1-$9
按顺序获取(字符串相关方法中),以后的正则中也能够经过\1-\9
进行引用(正则表达式内部)。(分组0表示整个正则匹配内容或整个正则表达式)
在正则表达式中,以上这些以及一些未列出的元字符都是有自身含义的,若是咱们须要匹配这些元字符自己,可使用
\
对其进行转义便可。
更多元字符能够查看:正则表达式
ignoreCase
:返回一个布尔值,表示是否设置了i修饰符,该属性只读。
global
:返回一个布尔值,表示是否设置了g修饰符,该属性只读。
multiline
:返回一个布尔值,表示是否设置了m修饰符,该属性只读。
sticky
:ES6返回一个布尔值,表示是否设置了y修饰符,只读。
var r = /abc/igm; r.ignoreCase; // true r.global; // true r.multiline; // true
lastIndex
:返回下一次开始搜索的位置。该属性可读写,可是只在设置了g修饰符时有意义。
source
:ES5返回正则表达式的字符串形式(不包括反斜杠),该属性只读。
flags
:ES6返回正则表达式中的修饰符。
var r = /abc/igm; r.lastIndex; // 0 r.source; // "abc" r.flags; //"igm"
正则对象的test
对象接收一个字符串,表示测试字符串,返回一个布尔值,表示是此字符串是否知足匹配条件。
telRegex1.test('13612341234'); // true telRegex2.test('13612341234'); // true telRegex1.test('136123412'); // false
若是正则表达式带有g
修饰符,则每一次test
方法都从上一次结束的位置开始向后匹配。同时,能够经过正则对象的lastIndex
属性指定开始搜索的位置。
var xReg = /x/g; var str = 'xyz_x1_y1_x3'; xReg.lastIndex; // 0 xReg.test(str); // true xReg.lastIndex; // 1 xReg.test(str); // true xReg.lastIndex; // 5 // 指定位置开始 指定下次匹配从最后一位开始,就匹配不到了 xReg.lastIndex = 11; // 11 xReg.test(str); // false xReg.lastIndex; // 0
var indexReg = /^(?:http|https).+\/jwebui\/pages\/themes\/(\w+)\/\1\.jspx(\?\S+)?$/i ;
上面是一个F8中检查是否为首页的正则表达式。
最开始的^
和最后的$
分别表示匹配的开始和结束。
(?:http|https)
表示二者之一,这么写是非获取的组匹配,()
不会被分组存储。也能够写成(http|https)
可是后面的\1
就须要替换成\2
了,由于这么写时此处造成了第一个分组。
.+
就是任意字符至少出现一次。
\/jwebui\/pages\/themes\/
就是匹配字符串"/jwebui/pages/themes/"
。
(\w+)
做为第一个分组,表示任意字母或数字或下划线或汉字至少出现一次。
\1
表示对第一个分组的引用,再重复第一分组的内容 。
\.jspx
表示.jspx
。
(\?\S+)?
表示(\?\S+)
匹配的内容出现0次或一次。其中:
\?
表示?
。
\S+
表示任意可见字符出现至少一次。
`
正则对象的exec
方法,能够返回匹配结果。若是发现匹配,就返回一个数组,成员是每个匹配成功的子字符串,不然返回null
。
若是正则表示式包含圆括号(即含有“组匹配”),则返回的数组会包括多个成员。第一个成员是整个匹配成功的结果,后面的成员就是圆括号对应的匹配成功的组。也就是说,第二个成员对应第一个括号,第三个成员对应第二个括号,以此类推。整个数组的length
属性等于组匹配的数量再加1。
var ipReg = /(\d{1,3}\.){3}(\d{1,3})/; var ipStr = 'My ip is "192.168.118.47" , please tell me yours'; ipReg.exec(ipStr); // ["192.168.118.47", "118.", "47"]
上面第一段代码表示一个简单的IP检验,数字的1-3位以后紧跟一个.
,接着这个总体要出现3次,最后再有一段数字的1-3位。结果数组中,第一个值表示匹配到的结果,以后的表示正则分组匹配到的内容。
若是正则表达式加上g修饰符,则可使用屡次exec方法,下一次搜索的位置从上一次匹配成功结束的位置开始。同时还能够指定lastIndex
,使之下次从指定位置开始(可见以前的test
示例)。
var ipLastReg = /\d+(?=;)/g; var ipsStr = '192.168.118.47;192.168.118.46;192.168.118.48;'; ipLastReg.exec(ipsStr); // ["47"] ipLastReg.exec(ipsStr); // ["46"] ipLastReg.exec(ipsStr); // ["48"]
上面代码中正则中的(?=;)
表示先行断言,表示只匹配在;
前面\d+
。
若是只是为了获得是否匹配,请使用
RegExp.test()
方法或字符串实例的.search()
替代,效率更高。
之因此称之为字符串相关方法是由于其是在字符串上调用的(虽然ES6开始,内部调用的是正则上的方法,但仍是在字符串上提供的入口)。
match()
:返回一个数组,成员是全部匹配的子字符串。
search()
:按照给定的正则表达式进行搜索,返回一个整数,表示匹配开始的位置。
replace()
:按照给定的正则表达式进行替换,返回替换后的字符串。
split()
:按照给定规则进行字符串分割,返回一个数组,包含分割后的各个成员。
match
方法对字符串进行正则匹配,返回匹配结果。此方法方法与正则对象的exec
方法很是相似:匹配成功返回一个数组,匹配失败返回null
。若是正则表达式带有g
修饰符,则该方法与正则对象的exec
方法行为不一样,会一次性返回全部匹配成功的结果。
var ipLastReg = /\d+(?=;)/g; var ipsStr = '192.168.118.47;192.168.118.46;192.168.118.48;'; ipsStr.match(ipLastReg); // ["47", "46", "48"]
上面的正则是匹配IP中的最后一位,其中使用了(?=;)
意为先行断言,表示只匹配在;
以前的内容,可是不包括;
。关于更多先行断言,请看下文。
search
方法,返回第一个知足条件的匹配结果(可直接使用字符串,不必定是正则对象)在整个字符串中的位置。若是没有任何匹配,则返回-1
。
var nowDateStr = '2016-11-1'; var testReg = /-/g; nowDateStr.search(testReg); // 4 // 再次查找仍是4 nowDateStr.search(testReg); // 4 // 检查lastIndex 并设置 testReg.lastIndex; // 0 testReg.lastIndex = 6; nowDateStr.search(testReg); // 4 结果仍为4
search
方法老是从字符串的开始位置查找,与正则表达式的g
修饰符和lastIndex
属性无关。
replace
方法能够替换匹配的值,返回替换后的新字符串。它接受两个参数,第一个是搜索模式(可直接使用字符串,不必定是正则对象),第二个是替换的内容(可以使用字符串或一个函数)。搜索模式若是不加g修饰符,就替换第一个匹配成功的值,不然替换全部匹配成功的值。
其中replace
方法的第二个参数可使用美圆符号$,用来指代所替换的内容,具体以下所示:
$&
指代匹配的子字符串。
$`
指代匹配结果前面的文本。
$'
指代匹配结果后面的文本。
$n
指代匹配成功的第n组内容,n是从1开始的天然数。
$$
指代美圆符号$。
var re = /-/g; var str = '2016-11-01'; var newstr = str.replace(re,'.'); console.log(newstr); // "2016.11.01" 'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1'); // "world hello" 'abc'.replace('b', '[$`-$&-$\']'); // "a[a-b-c]c"
第二个参数为函数:
function toCamelStyle(str) { // 匹配-以及以后的一个字符,其中这个字符在一个分组内 var camelRegExp = /-([a-z])/ig; return str.replace(camelRegExp, function(all, letter) { // all为匹配到的内容,letter为组匹配 return letter.toUpperCase(); }); } toCamelStyle('margin-left'); // "marginLeft" toCamelStyle('aa-bb-cccc'); // "aaBbCccc"
以上代码展现经过正则将aa-bb-cccc
这样的字符串转化为aaBbCccc
这种形式。replace
回调函数接收两个参数,第一个为匹配到的内容,第二个为匹配到的分组,有多少组就能够传多少个参数,在此以后还能够有两个参数,一个为匹配到内容在原字符串的位置,另外一个是原字符串。
split
方法按照正则规则分割字符串,返回一个由分割后的各个部分组成的数组。该方法接受两个参数,第一个参数是分隔规则(可直接使用字符串,不必定是正则对象),第二个参数是返回数组的最大成员数。
'2016-11-01'.split('-'); // ["2016", "11", "01"] '2016-11-01'.split(/-/); // ["2016", "11", "01"]
当正则表达式中包含能接受重复的限定符时,一般的行为是(在使整个表达式能获得匹配的前提下)匹配尽量多的字符,称之为贪婪模式。
例如:
var s = 'aaa'; s.match(/a+/); // ["aaa"]
有时,咱们更须要懒惰匹配,也就是匹配尽量少的字符。前面给出的限定符均可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,可是在能使整个匹配成功的前提下使用最少的重复。
var s = 'aaa'; s.match(/a+?/); // ["a"]
如下是一些说明
*?
重复任意次,但尽量少重复
+?
重复1次或更屡次,但尽量少重复
??
重复0次或1次,但尽量少重复
{n,m}?
重复n到m次,但尽量少重复
{n,}?
重复n次以上,但尽量少重复
也就是说默认状况下,都是贪婪模式,加上一个?
时就转化为了懒惰模式,也称非贪婪模式。
一般一个()
中的内容就构成了一个分组,此分组内容将被存储,可在以后的正则表达式(使用\1-\9
)和相关方法中(使用 $1-$9
)引用,前面已经介绍过了,就再也不说了。
关于组匹配,还有如下几种状况:
(?:x)
称为非捕获组(Non-capturing group),表示不返回该组匹配的内容,即匹配的结果中不计入这个括号。
// 正常匹配 var url = /(http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec('http://google.com/'); // ["http://google.com/", "http", "google.com", "/"] // 非捕获组匹配 var url = /(?:http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec('http://google.com/'); // ["http://google.com/", "google.com", "/"]
以后先行断言和先行否认断言也都是非捕获组
x(?=y)
称为先行断言(Positive look-ahead),x
只有在y
前面才匹配,y
不会被计入返回结果。
好比以前匹配ip的例子:
var ipLastReg = /\d+(?=;)/g; var ipsStr = '192.168.118.47;192.168.118.46;192.168.118.48;'; ipsStr.match(ipLastReg); // ["47", "46", "48"]
上面正则对象中(?=;)
就表示只匹配在;
以前的内容,可是不包括;
。
x(?!y)
称为先行否认断言(Negative look-ahead),x
只有不在y
前面才匹配,y
不会被计入返回结果。
var xreg = /\d+(?!%)/g ; xreg.exec('100% is 1'); // ["10"] xreg.exec('100% is 1'); // ["1"] /\d+?(?!%)/.exec('100% is 1'); // ["1"]
上面代码表示匹配不在%
前的数字,xreg
中直接书写的\d+
表示贪婪模式,所以第一次匹配到的是10,第二次才会匹配到后面的1,由于做为数字10自己也不在%
前面,正则不会将100当成一个总体(注意:这里须要定义一个正则对象来调用,直接以字面量形式的正则调用时,每次调用都是一个新对象,结果始终是10
)。
为了一次匹配到最后的1
,咱们在\d+
以后加一个?
将其转为非贪婪模式便可。
为了一次匹配到前面100
中的1
,咱们在\d+
以后加一个?
将其转为非贪婪模式便可。
ES6以前,
JavaScript
中不支持后行断言和否认后行断言,ES6中添加了对此的支持,请看以后的ES扩展部分。
RegExp构造函数的参数有两种状况。
第一种状况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。
第二种状况是,参数是一个正则表示式,此时不能有第二个参数,会返回一个原有正则表达式的拷贝。
ES6 针对第二种状况,容许传入第二个参数,用于设置第一个参数正则表达式的修饰符。
var regex = new RegExp(/xyz/, 'i'); // ES6以前 语法错误 new RegExp(/abc/ig, 'i'); // ES6中结果为: /abc/i
字符串对象共有4个方法,可使用正则表达式:match()
、replace()
、search()
和split()
。
ES6将这4个方法,在语言内部所有调用RegExp
的实例方法,从而作到全部与正则相关的方法,全都定义在RegExp对象上。
ES6对正则表达式添加了u
修饰符,含义为“Unicode
模式”,用来正确处理大于uFFFF的Unicode字符。也就是说,会正确处理四个字节的UTF-16编码。
ES6还为正则表达式添加了y
修饰符,叫作“粘连”(sticky
)修饰符。
y
修饰符的做用与g
修饰符相似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不一样之处在于,g
修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
var s = 'aaa_aa_a'; var r1 = /a+/g; var r2 = /a+/y; // 第一次都能正确匹配 r1.exec(s); // ["aaa"] r2.exec(s); // ["aaa"] // 第二次结果就不一致了 r1.exec(s); // ["aa"] r2.exec(s); // null
我的理解,\y
是相似于在每次匹配时隐式地添加了^
,表示开始位置。
ES5中,正则对象存在source
属性,用于返回正则表达式自己。
ES6中,又添加了flags
属性,用于返回正则对象的全部修饰符。
后行断言于先行断言相反。例如/(?<=y)x/
表示匹配x
,可是要求x
必须在y
后面。
同理 后行否认断言则为:/(?<!=y)x/
表示匹配x
,可是要求x
不能在y
后面。
须要注意的是,存在后行断言时,正则执行顺序发生了改变,会先匹配后行断言的这部分,再匹配其余的的,顺序变成了从右向左。所以一些匹配操做的结果可能大不一致,并且正则中的
\1-\9
的引用顺序也会发生变化。
原文发表在个人博客JavaScript正则表达式RegExp,欢迎访问!
先行否认断言中
为了一次匹配到最后的1
,咱们在\d+
以后加一个?
将其转为非贪婪模式便可。
为了一次匹配到前面100
中的1
,咱们在\d+
以后加一个?
将其转为非贪婪模式便可。