javascript正则表达式
最近本仙女正在筹划减肥事宜
然鹅 才吃了两个晚上的果蔬 就放弃战斗了
太乏了
<-----------------------------------蜜汁分割线----------------------------------->
谈正事,正则表达式为什么存在呢?
我想大概是因为计算机并不能了解人心!
比方说,你想要美女的企鹅号,那计算机肯定不知道啥是企鹅号,更不会知道啥叫美女,就会给你一些乱七八糟的东西,
这样直男癌就会很懊恼,就要给他制定一些规则,那每个人心中的美女又各有不同,所以告诉他想要的企鹅号形式就行了:
【首位不是0啊,必须是5-12位啊,还想要笔芯520的啊啥啥的】
那计算机立马就聪明起来了,早这么说不就知道了,自己去文中找吧!
一、定义正则
1.字面量形式
以斜杠(/)开始和结束
var re = /w1569178479/ // 计算机说欢迎泥萌加我的卫星号
2.RegExp构造函数
var re = new RegExp('w1569178479') // 可接受第二个参数,后面再讲
上面两种写法是等价的,但是第一种字面量形式比较常用、性能更好
注:
- 字面量形式时,双斜杠内不能为空
- 字面量形式时,双斜杠内是连续的字符串,空格通常用\s显示
- 当正则表达式内需要用变量表示时,用RegExp构造函数形式创建正则表达式对象
二、常用方法
正则的常用方法分为两类,
一类是正则的实例方法,用法:正则.方法(字符串)
一类是字符串的实例方法,用法:字符串.方法(正则)
1.正则的实例方法
(1)test():在参数字符串中查找匹配的正则内容,返回值为布尔值
/wzy/.test("weizeyang or wzy") // true
上述代码验证test方法内的参数字符串是否包含正则表达式内的wzy,结果返回值为true说明包含
如果正则模式是一个空字符串,则匹配所有字符串(上面提过当正则为空字符串时不能用双斜杠,这时会以为是注释)
new RegExp('').test("weizeyang or wzy") // true
栗子:匹配非数字加空格的字符串
/\D\s/.test("wzy123 wzy") // false /\D\s/.test("wzy123 wzy ") // true
其中\D表示非数字(\d表示数字)、\s表示空格,所以第二行代码的'wzy '是符合的即是非数字的后面又含有空格
(2)exec():用来返回匹配结果,返回值为数组,成员是匹配成功的子字符串
注:
- 当没有匹配值时,返回值是null
- 永远只返回第一个匹配值和其相关信息,即使是全局匹配(g)也只返回第一个
- 返回值的相关信息包含两个额外的属性:index 和 input。其中,index 表示匹配项在字符串中的位置,而 input 表示应用正则表达式的字符串
栗子:
/(\w+)(\d)\.(\d)/g.exec("web2.0 .net2.0") // 全局匹配 /(\w+)(\d)\.(\d)/.exec("web2.0 .net2.0") // 非全局匹配 // 全局匹配和非全局匹配返回结果一样
返回值:
其中:
- \w :字符 ( 字母 ,数字,下划线_ )
- + :匹配一次或者多次
- \d : 数字
- () :分组符,相当于数学里面的小括号
- \. :就是表示一个点,如果没有加转义斜杠(\)那就表示任意字符
- g :全局匹配
所以上述正则
/(\w+)(\d)\.(\d)/g
表示:在字符串中全局(g)匹配 -> 含有一个或者任意个字符 + 数字 + 点 + 数字
相对应的匹配出来的是 -> web + 2 + . + 0(也就是返回数组的第一项)
那就有两个疑问了:
(1)当全局匹配时,net + 2 + . + 0 也是匹配该正则模式的,由于exec()只返回第一个匹配项,所以只返回了web2.0,但是可以进行二次匹配,或者用循环进行多次匹配
如下当全局匹配时(g),第一次匹配是从第一位开始匹配的,下次再匹配是从上次结束的位置开始的
如果想第二次匹配也从第一位开始,那么要设置正则的一个属性lastIndex,指定进行匹配的起始位置
lastIndex属性可读写,但是只在设置了g修饰符、进行连续搜索时有意义
(2)返回值数组中第一个成员是匹配值,那其余成员是什么呢?
后面的"web","2","0"是由于正则表达式里面使用了小括号分组匹配,小括号内的内容会作为子项返回回来,分别对应 (\w+) ,(\d),(\d)
2.字符串的实例方法
(1)match():该方法和上述的exec()方法相似,有一点不同的就是全局(g)匹配会一次性返回所有匹配成功的结果
非全局匹配(返回的结果和exec()一样)
全局匹配,会真的全局进行匹配,但这时不返回额外属性(返回了上述我们提到过的匹配值net2.0)
注:设置正则表达式的lastIndex属性,对match方法无效,匹配总是从字符串的第一个字符开始。
栗子:
var str = 'haj123sdk54hask33dkhalsd879'; var re = /\d+/g; str.match(re) // [123,54,33,879]
- \d:数字
- +:至少出现一次、匹配不确定的次数
上述正则 /\d+/g 表示 在全局匹配至少一个数字
当正则为 /\d+/ 时 返回值为 与exec()相同返回第一个匹配值
当正则为 /\d/g 时 返回值为因为这时正则匹配的是数字,只要匹配就返回
(2)search():返回第一个在字符串中匹配成功的位置,如果没有任何匹配则返回-1
"wzy123".search(/\bw/i) // 0 "wzy123".search(/\BW/i) // -1 "wzy123".search(/\Bz/i) // 1
- \b:边界(起始,结束,空格)
- \B:内部
- i:修饰词表示不区分大小写
之前说过 RegExp构造函数可以传第二个参数,如下
var reg = new RegExp('\\bW','i') // 这里注意预定义的特殊字符\b前面需要多加一个转义的斜杠,才能正常输出 var str = "wzy123" str.search(reg) // 0
(3)replace():匹配正则并进行替换,有两个参数,第一个参数表示要匹配的正则,第二个参数表示要进行替换的字符串,返回值为替换后的字符串
用法:原字符串.replace(正则,进行替换的字符串)
栗子:消除首尾两端的空格
var str = ' #id div.class '; str.replace(/^\s+|\s+$/g, '') // "#id div.class"
其中:
- ^:行的起始位置
- \s:空格
- |:或
- $:行的结束位置
上述正则解释:将匹配正则-全局匹配起始位置的(至少一个)空格或结束位置的(至少一个)空格替换成空
当不加全局匹配修饰符时,返回结果为"#id div.class ",即满足|前面的则停止匹配
注:
1.replace的第二个参数也可以用$来指代所替换的内容
- $&:匹配的子字符串
- $`:匹配结果前面的文本
- $’:匹配结果后面的文本
- $n:匹配成功的第n组内容,n是从1开始的自然数
- $$:指代美元符号$
'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1') // $2表示正则匹配第二个小括号里面的子字符串 // "world hello" 'abc'.replace('b', '[$`-$&-$\']') // \'将单引号转义了一下 // "a[a-b-c]c"
2.replace的第二个参数也可以是一个函数,将每一个匹配内容替换为函数返回值
"wzy 12 3 or weizeyang123".replace(/(\w+\s)[0-9]+/g, function(a1,a2,a3,a4) { console.log(a1,a2) // "wzy 12" "wzy " "0" "wzy 12 3 or weizeyang123" return a1 + "-" + a2; });
// "wzy 12-wzy 3 or weizeyang123"
当replace的正则中有子项的时候,
第一个参数:a1表示匹配正则成功后的字符串
第二个参数:a2表示匹配成功的第一个子项(依次第二第三个子项为第二个第三个参数),本栗即上述小括号里面的,打印出来为"wzy "
倒数第二个参数:a3表示a1在原字符串中出现的位置
倒数第一个参数:a4表示原字符串
- \w:字符(数字,字母,下划线)
- \W:非字符
- []:表示集合中的任意一个,有两种表示[abc]或者[a-c]
(4)split():按照正则规则分割字符串,返回一个由分割后的各个部分组成的数组
用法:(可接受两个参数)字符串.split(正则,返回数组的最大成员数)
"w|z|y |wzy".split(/\|\s*/) // 这里的竖线(|)由于和正则中的“或”字符冲突所以要加转义// ["w", "z", "y ", "wzy"] "w|z|y |wzy".split(/\|\s*/,2) // ["w", "z"]
上面代码表示以竖线及0个或0个以上空格进行分割
- *:表示0或0个以上
'aaa*a*'.split(/a*/) // [ '', '*', '*' ] 'aaa**a*'.split(/a*/) // ["", "*", "*", "*"] 'aaa*a*'.split(/(a*)/) // [ '', 'aaa', '*', 'a', '*' ]
注:当正则表达式使用括号时,括号匹配的内容都会作为数组成员返回
三、匹配规则
1.字面量和元字符
大部分字符在正则表达式中,就是字面的含义,如/a/匹配a,这样的就叫做"字面量字符"
出了字面量字符以外,还有一部分字符有特殊意义,不代表字面的意思,它们叫做"元字符"
名称 | 匹配对象 | |
. | 点号 | 单个任意字符(除回车\r、换行\n、行分隔符\u2028和段分隔符\u2029外) |
[] | 字符组 | 列出的单个任意字符 |
[^] | 排除型字符组 | 未列出的单个任意字符 |
? | 问号 | 匹配0次或1次 |
* | 星号 | 匹配0交或多次 |
+ | 加号 | 匹配1次或多次 |
{min,max} | 区间量词 | 匹配至少min次,最多max次 |
^ | 脱字符 | 行的起始位置 |
$ | 美元符 | 行的结束位置 |
| | 竖线 | 或 |
() | 括号 | 限制多选结构的范围,标注量词作用的元素,为反向引用捕获文本 |
\1,\2... | 反向引用 | 匹配之前的第一、第二...组括号内的表达式匹配的文本 |
注:
-
正则表达式中那些有特殊含义的元字符,如果要匹配它们本身,就需要在它们前面加上反斜杠进行转义,比如要匹配+,就要写成\+
-
正则表达式中,需要转移的,一共有12个字符:^、.、[、$、(、)、|、*、+、?、{、\\
-
如果使用RegExp方法生成正则对象,转移需要使用两个斜杠,因为字符串内部先转义一次
2.特殊字符
匹配对象 | |
\cX | 表示Ctrl-[X] ,其中的X 是A-Z之中任一个英文字母,用来匹配控制字符 |
[\b] | 匹配退格键(U+0008),不要与\b 混淆 |
\n | 匹配换行键 |
\r | 匹配回车键 |
\t | 匹配制表符 tab(U+0009) |
\v | 匹配垂直制表符(U+000B) |
\f | 匹配换页符(U+000C) |
\0 | 匹配null 字符(U+0000) |
\xhh | 匹配一个以两位十六进制数(\x00 -\xFF )表示的字符 |
\uhhhh | 匹配一个以四位十六进制数(\u0000 -\uFFFF )表示的 Unicode 字符 |
3.预定义模式
连接符(-):默写情况下,对于连续序列的字符,连字符用来提供简写,表示字符的连续范围。比如[012345]写成[0-5],前提是在方括号[]中使用。
匹配对象 | |
\d | 匹配0-9之间的任一数字,相当于[0-9] |
\D | 匹配所有0-9以外的字符,相当于[^0-9] |
\w | 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_] |
\W | 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_] |
\s | 匹配空格(包括换行符、制表符、空格符等),相等于[\t\r\n\v\f] |
\S | 匹配非空格的字符,相当于[^\t\r\n\v\f] |
\b | 匹配词的边界 |
\B | 匹配非词边界,即在词的内部 |
栗子:
var html = "<b>Hello</b>\n<i>world!</i>"; /.*/.exec(html)[0] // "<b>Hello</b>"
上面代码中包括换行符,结果点字符(.)不匹配,这时使用\s字符类,就能包括换行符。
var html = "<b>Hello</b>\n<i>world!</i>"; /[\S\s]*/.exec(html)[0] // "<b>Hello</b>\n<i>world!</i>"
注:[\S\s]指代一切
4.量词符
匹配对象 | |
{n} | 匹配n次 |
{n,m} | 匹配至少n次,最多m次 |
{n,} | 匹配至少n次 |
? | 相当于{0,1} |
* | 相当于{0,} |
+ | 相当于{1,} |
栗子:
"wwwwzy".match(/w{2}/g) // ["ww", "ww"] "wwwwzy".match(/w{2,5}/g) // ["wwww"] "wwwwwwwwwwzy".match(/w{2,}/g) // ["wwwwwwwwww"]
5.贪婪模式与非贪婪模式
默认情况下,量词都是贪婪模式,即匹配到下一个字符不再满足匹配规则为止
非贪婪模式就是在量词后面加一个?,表示尽可能少的匹配,一旦满足就不再往下匹配
"wwwwzy".match(/w{2}?/g) // ["ww", "ww"]
"wwwwzy".match(/w{2,5}?/g) // ["ww", "ww"]
"wwwwwwwwwwzy".match(/w{2,}?/g) // ["ww", "ww", "ww", "ww", "ww"]
"wwwwwwwwwwzy".match(/w+?/g) // ["w", "w", "w", "w", "w", "w", "w", "w", "w", "w"]
"wwwwwwwwwwzy".match(/w*?/g) // ["", "", "", "", "", "", "", "", "", "", "", "", ""]
6.组匹配
(1)捕获组
上面已经简述过小括号的用法,现在就搬几个阮一峰大神的栗子看下
栗子1:
/fred+/.test('fredd') // true /(fred)+/.test('fredfred') // true
第一行代码的+字符只重复字母d,第二个加了括号进行分组的代码+字符会匹配整个括号内的内容
栗子2:
/(.)b(.)\1b\2/.exec("abcabcde") // ["abcabc","a","c"]
上面代码,\1表示第一个括号内的内容即a,\2表示第二个括号的内容c
/y(.)(..)\2\1/.exec('yabbbbab') // ["yabbbba", "a", "bb"]
一个点(.)表示任意一个字符
/y((..)\2)\1/.exec('yabababab') // ["yabababab", "abab", "ab"]
括号可以进行嵌套,\1表示外面的括号,\2表示里面的括号,即\2表示重复(..)的内容使得(..)\2匹配为abab,\1表示再重复一遍(..)\2的内容使得((..)\2)\1匹配为abababab
下面是一个匹配网页标签的栗子:
var tagName = /<([^>]+)>[^<]*<\/\1>/ tagName.exec("<b>bold</b>") // ["<b>bold</b>", "b"]
上面正则表达式有点繁琐但也不难,
/<([^>]+)>[^<]*<\/\1>/
绿色部分:匹配尖括号<>
橙色部分:匹配尖括号内的内容,第一个橙色表示排除(^)右尖括号(>)以外的至少一个字符,第二个橙色\1表示和上一个一样圆括号里面的内容
蓝色部分:匹配排除(^)左尖括号(<)以外的0或0个以上的字符
红色部分:将反斜杠(\/)转义输出
(2)非捕获组
在使用组匹配的时候,有时不想输出组匹配的内容,只想得到整个匹配内容,这时可以用(?:x)形式进行匹配
'wzy'.match(/(?:.)z(.)/) // ["wzy","y"] 'wzy'.match(/(.)z(.)/) // ["wzy","w","y"]
上述第一行代码在使用了非捕获组(?:x)时没有输出改组匹配的内容即"w"
(3)先行断言
先行断言x(?=y),只有x在y前面才匹配,其中y不会被作为结果返回
'abc'.match(/b(?=c)/) // ["b"] 'abc'.match(/b(?=d)/) // null 'abc'.match(/c(?=b)/) // null 'abc'.match(/c(?=c)/) // null
(4)先行否定断言
先行否定断言x(?!y),只有x不在y前面才匹配,其中y不会被作为结果返回
'abd'.match(/b(?!c)/) // ["b"] 'abcd'.match(/b(?!c)/) // null 'abcd'.match(/d(?!c)/) // ["d"] 'abcd'.match(/c(?!c)/) // ["c"]
7.修饰符
在上面的例子中已经见到过,正则的修饰符有三个分别为:i、g、m,放在正则模式的尾部,或RegExp的第二个参数中,可同时使用
(1)i:不区分大小写
(2)g:全局匹配
var regex = /b/; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // true
上述代码的三次匹配,每次都是从字符串str的第一个字符开始匹配,所以三次匹配到的都是第二位置的b
var regex = /b/g; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // false
当加上全局匹配g之后,第一次之后的匹配均从上次匹配结尾处开始,所以第二次匹配的是第三位置的b,第三次匹配从abb位置往后再无匹配结果返回false
(3)m:多行模式
/world$/.test('hello world\n') // false /world$/m.test('hello world\n') // true
第一行代码匹配结尾是world,由于字符串后有个换行符所以匹配失败
第二行代码加上m修饰符后,匹配成功
即m修饰符会修改^和$的行为,默认情况下,^和$匹配字符串的开始出和结尾处,加上m之后,还会匹配行首和行尾,所以会识别换行符
/^b/m.test('a\nb') // true
8.优先级
匹配对象 | |
\ |
转义符 |
() (?!) (?=) [] |
括号、字符组、环视 |
* + ? {n} {n,} {n,m} |
量词 |
^ $ |
起始结束位置 |
| |
选择 |
四、js常用的表单正则验证
五、参考链接
1.http://javascript.ruanyifeng.com/stdlib/regexp.html#toc9
2.https://www.cnblogs.com/moqing/archive/2016/07/13/5665126.html