javascript正则表达式

最近本仙女正在筹划减肥事宜

 

然鹅 才吃了两个晚上的果蔬 就放弃战斗了

太乏了

 

<-----------------------------------蜜汁分割线----------------------------------->

 

谈正事,正则表达式为什么存在呢?

我想大概是因为计算机并不能了解人心!

比方说,你想要美女的企鹅号,那计算机肯定不知道啥是企鹅号,更不会知道啥叫美女,就会给你一些乱七八糟的东西,

这样直男癌就会很懊恼,就要给他制定一些规则,那每个人心中的美女又各有不同,所以告诉他想要的企鹅号形式就行了:

【首位不是0啊,必须是5-12位啊,还想要笔芯520的啊啥啥的】

那计算机立马就聪明起来了,早这么说不就知道了,自己去文中找吧!

一、定义正则

1.字面量形式

以斜杠(/)开始和结束

var re = /w1569178479/   // 计算机说欢迎泥萌加我的卫星号

2.RegExp构造函数

var re = new RegExp('w1569178479')  // 可接受第二个参数,后面再讲

上面两种写法是等价的,但是第一种字面量形式比较常用、性能更好

注:

  1. 字面量形式时,双斜杠内不能为空
  2. 字面量形式时,双斜杠内是连续的字符串,空格通常用\s显示
  3. 当正则表达式内需要用变量表示时,用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():用来返回匹配结果,返回值为数组,成员是匹配成功的子字符串

注:

  1. 当没有匹配值时,返回值是null
  2. 永远只返回第一个匹配值和其相关信息,即使是全局匹配(g)也只返回第一个
  3. 返回值的相关信息包含两个额外的属性: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... 反向引用 匹配之前的第一、第二...组括号内的表达式匹配的文本

注:

  1. 正则表达式中那些有特殊含义的元字符,如果要匹配它们本身,就需要在它们前面加上反斜杠进行转义,比如要匹配+,就要写成\+

  2. 正则表达式中,需要转移的,一共有12个字符:^、.、[、$、(、)、|、*、+、?、{、\\

  3. 如果使用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

3.https://www.cnblogs.com/onepixel/p/5218904.html

4.https://www.cnblogs.com/xiaohuochai/p/5608807.html

posted @ 2018-03-01 11:24  约爱丽丝下午茶  阅读(210)  评论(0编辑  收藏  举报