JS 正则表达式:(RegularExpression)
正则表达式的含义:
正则表达式是一种字符串匹配模式,在javascript中的作用主要是用来匹配特定形式的字符。
定义一个正则表达式:
我们想要定义一个正则表达式有两种方法:
- 正则表达式直接量
- 创建正则表达式对象
正则表达式直接量:
var reg = /s$/
我们可以使用正则表达式直接量来创建一个正则表达式,其中格式为/xxx/
,用两个反斜杠来表示正则表达式创建的格式,反斜杠中间写上我们要匹配的字符文本。
创建正则表达式对象:
var reg2 = new RegExp("s$")
用RegExp
构造函数创建正则表达式其实也是很简单的,构造函数接收一个参数,参数类型为字符串类型。传入的字符串就是我们要匹配的字符串的模板。new RegExp()
返回一个正则表达式对象。
注意:和js
中其他直接量不同,正则表达式的直接量会在代码执行的时候会把/s$/
转变成一个RegExp对象
,在旧版本的es3中,当执行到同一段正则表达式的时候会返回相同的对象。举个例子:
function createRegExp(){
var reg = /S$/
return reg
}
var myreg1 = createRegExp()
var myreg2 = createRegExp()
console.log(myreg1 === myreg2)//true
我们定义了一个函数,用来创建一个正则表达式对象。在全局,我们执行了两次createRegExp()
构造函数,将生成的正则表达式对象分别存放在myreg1
和myreg2
中,当我们将其做相等运算时发现,它们指向的是相同的一个对象,也就是说,在es3中,用正则表达式常见的RegExp对象会共享同一个实例。其实这个结论的前提是正则表达式的模式要一致。但是在es5中则是两个相对独立的表达式对象:
console.log(myreg1 === myreg2)//false
myreg1和myreg2是相互独立的,并不都会相互共享内存信息。如:lastIndex
后续有讲到。
直接量字符:
当我们想要去匹配非法的字符的时候,比如/
的时候,我们需要对字符进行转移。通常的做法是在非法的字符前面加上\
,即右斜杠。
在正则表达式中,有一些字符有它自己独特的含义,这些字符有:^ $ . * + = ! : | \ / ( ) [ ] { }
等,当我们使用这些符号的时候,它代表的意义已经不是我们字面上所看到的了,假如我们真的只是想单纯的想去匹配这些字符怎么办呢,我们需要对这些字符进行转义,假如我们想要匹配一个+
。
var reg = /+/
上面的写法肯定是不行的,原因是它代表特殊的匹配含义,想要单纯的匹配字符我们应该这样:
var reg = /\+/
我们需要用右斜杠将其转义后就可以单纯的匹配+
字符了。
字符类:
将直接量字符单独放进方括号[]
内可以组成一个字符类。一个字符类可以匹配它所包含的任意字符。我的理解是,字符类相当于一个集合,这个集合里面放着我们定义的字符。例如:
var reg = /[abc]/
注意:不用打逗号来表示分割,即不要[a,b,c]
这样的话,
也成为了我们字符类里的成员。
上面的表达式的意思是:现在我有一个集合,集合里面放的有a
,b
,c
这三个元素,那么正则表达式就用这个集合里的任意一个元素进行匹配。另外,我们可以用^
来否定字符类,^
符号在正则表达式的意思类似于我们编程语言中!
的意思,即为非,[^abc]
表示剔除掉集合中的所有元素,就是匹配集合的补集,除了集合中的元素,其他的元素都可以匹配。
[]
表示的是字符类,但是有一点值得注意,一个[]
代表一个字符,只不过这个字符可能是集合中的任意一个字符。什么意思呢,比如:
var str = '1234a'
var reg = /[asdfg]/
//现在我们的集合里面有a,s,d,f,g这五个元素,但是在匹配的时候只能和字符串中的一个进行匹配。
//先和str中的1匹配,看自己的集合中有没有这个字符,如果没有再和2匹配,看自己的集合里有没有这个字符
//以此类推,中括号里有五个字符,并不代表它一次能和字符串中的五个字符匹配。而是一个一个的匹配。
字符类可以使用连字符-
,来表示字符的范围。如:[a-zA-Z0-9]
:表示这个集合里面的元素是大小写字母和数字。每一个[]
其实都有一个自己的集合。就算你这样写[(ab)(cd)]
他也只是表示他的集合中有(/a/b/)/c/d
这六个字符。
在js中,有一些特定的字符类:
[...]
:方括号内的任意字符。也就是说这个集合里的元素是所有的字符。[^...]
:不在方括号内的任意字符。也就是说是[...]
集合的补集,也就相当于这个集合为空,它匹配不了任何字符。.
:除了换行符和其他Unicode行终止符之外的任意字符。\w
:任何ASCII组成的单词,等价于:[a-zA-Z0-9]
。\W
:(大写),任何不是ASCII组成的单词。等价于:[^a-zA-Z0-9]
\s
:任何Unicode空白符。\S
:任何非Unicode空白符的字符。注意:\w
和\S
不一样。\d
:任何ASCII数字。等价于[0-9]
。\D
:除了ASCII数字之外的任何字符,等价于:[^0-9]
。[\b]
:退出直接量(特例)
在方括号内可以写这些特殊转义字符,比如:[\w\s]
他代表的含义是匹配任何ASCII组成的单词和任何Unicode空白符。也就是说[\w\s]
字符类的集合是\w
和\s
的并集。
重复:
我们现在学的正则表达式只能匹配单个字符。意思是单个单个的字符匹配,无论是字符类还是使用特定的字符类。它们的区别只是对应集合的差异,在匹配的行为上,都是一次只能对一个字符进行匹配。假如我们要对多个字符进行匹配怎么办。有人会想到,我可以直接/abcd/
,这样就可以一次性匹配四个字符了,也就是四个四个的去匹配。这样固然可以,但是有局限性。就是限定死了匹配的内容,只能匹配abcd这四个字。现在我们的需求是匹配两个任意的数字。那么我们应该怎么办呢?我们可以这样写:
var reg = /\d\d/
//这样就可以表示一次性匹配两个数字了
但是这样写有一个缺点,假如我们要同时匹配100个数字,难道我们要写100个\d
吗。正则表达式对于重复有自己的相关优化。
下面是正则表达式的重复字符语法:
{n,m}
:匹配前一项至少n次,但不能超过m次。{n,}
:匹配前一项n次或者更多次。{n}
:匹配前一项n次。?
:匹配前一项0次或者1次,也就是说前一项是可选的,等价于{0,1}
。+
:匹配前一项1次或多次,等价于{1,}
。*
:匹配前一项0次或多次,等价于{0,}
。
上面的次
不是匹配的次数,而是一次要同时匹配几个字符。即以几个字符为单位去匹配。
我们来解决我们前面提到的需求,此时我们要匹配两个数字(两个两个的匹配,两个数字为一次匹配单位),则可以这样写:
var reg =/\d{2}/
实例:
这里有几个实例:
var reg1 = /\d{
2,4}/ //匹配2~4个数字
var reg2 = /\w{
3}\d?/ //精确匹配三个单词和一个可选数字
var reg3 = /\s+javascript\s+/ //匹配前后都带有一个或者多个空格的"javascript"字符串
var reg4 = /[^(]*/ //匹配0个或者多个的非(的字符
因为*
和?
允许字符的匹配可以为0,所以它们允许什么都不匹配。
重复的特性:
贪婪匹配:
我们在分析前面正则表达式重复语法的时候发现,大多数的语法都允许我们去匹配多个。现在我们想一个问题,我有一个字符串,然后有一个reg
var str = "aaaa"
var reg = /a+/
此时问题就来了,因为+
是允许我们去匹配一个或者多个字符。那么我们是匹配一个还是两个亦或者全部呢?答案是会匹配全部。在一般情况下,正则表达式使用的是贪婪匹配。即尽可能多的匹配。
非贪婪匹配:
假如我们不想进行贪婪匹配,我们可以使用非贪婪匹配,当我们使用非贪婪匹配的时候,只需要在待匹配的字符后面跟随一个?
即可。例如:??
,+?
,*?
,{1,3}?
。比如正则表达式/\d{2,4}?/
他也可以匹配两个或四个数字,但是它会尽可能少的匹配。这里挺有意思的,我们仔细思考什么叫尽可能少的匹配。也就是说在默写特定的情况下即使你使用了?
也不能以最少的来匹配。这就引除了一条重要的概念:
正则表达式的模式匹配总是会寻找字符串中第一个可能匹配的位置。
例如:
var str = "aaaab"