最近复习JavaScript基础知识夯实基础,发现有很多短板。其中之一便为正则表达式,在进行了相对系统的总结学习之后,在这里做一番自己的总结。以备之后便捷查询更改。
概念:
正则表达式也被称为规则表达式,通常被用于检索,替换某些规则的文本。
不必对概念纠结,简单的将正则表达式理解为一个匹配规则即可。
作用:
正则表达式在不同的编程语言中有着不同的表现形式,在这里使用JavaScript前端语言进行举例并且说明
经常会遇见一个替换场景,例如将字符串'a1b1c1d1'
中的数字全部替换成大写字母X
'a1b1c1d1'.replace('1', 'X') // 结果为: 'aXbXcXdX'
但是当需要替换字符串'a1b2c3d4'
中的所有的数字为大写字母X时需要怎么做?
是不是有些繁琐,在这里使用正则表达式将会非常的方便
'a1b2c3d4'.replace(/\d/g, 'X') // 结果为: 'aXbXcXdX'
即使不使用正则表达式他也会将匹配字符转换成正则规则,再进行匹配,因此使用正则将会更加方便
1:创建正则的两个方式
在javascript中,通常通过使用内置对象:RegExp对象来支持使用正则表达式
1):通过创建变量的方式(常用)
var reg = /\d/g;
2):通过创建对象的方式
var reg = new RegExp('\\d', g)
// 第一个参数为正则表达式,在字符串中\属于特殊字符, 因此必须要进行转义;
// 第二个参数是修饰符,
2:正则表达式的修饰符
3:正则表达式的两种字符类型
* + ? $ ^ . | \ ( ) { } [ ]
4:正则表达式的类
在描述表达式中的类之前,大家都明白,凡是类,必定就是一个泛指,他代表的是一类字符。
1:字符类
使用【】来构建类
【abc】表示将a或b或c归为一类,表示one of,有其中一个即可。
注意常用字符类取反^
【^abc】 表示 none of 不属于这三者中的任意一个。
2:范围类
如果只是用字符类去匹配某几个字符,可以以字符类的形式直接写出来,但是当匹配的是所有的数字,或者是26个字母时,如果全部都列举出来例如[0123456789]
是不是麻烦了一点? 此时就需要范围类。
[0-9] // 表示所有的数字
[a-z] // 表示所有的小写字母
[A-Z] // 表示所有的大写字母
[a-zA-Z] // 表示所有的大小写字母
5:JavaScript中正则表达式的预定义类和边界
1:预定义类
在正则表达式中有很多的预定义的类,用于替换写法较为繁琐的正则。
预定义类 | 等价类与意义 |
---|---|
. | [^\r\n]除回车符和换行符外的所有字符 |
\d | [0~9] 数字字符 |
\D | [^0~9]非数字字符 |
\s | [\t\n\x0B\f\r]空白字符 |
\S | [^\t\n\x0B\f\r]非空白字符 |
\w | [a-zA-Z_0-9]单词字符(字母数字下划线) |
\W | [^a-zA-Z_0-9]非单词字符 |
2:边界
例如有字符串 This is a boy
需要匹配单词is,
var reg = /\bis\b/g
此时就需要使用单词边界 \b
边界 | 含义 |
---|---|
^ | 以XX开始(在正则的前面进行添加) |
$ | 以XX结束(在正则的后面添加) |
\b | 单词边界 |
\B | 非单词边界 |
6:正则表达式的量词
当一个字符出现多次时,将匹配规则重写多次是不现实的,况且也不知道他具体出现的次数,因此量词的出现就更加具有意义。
量词符号 | 等价写法与意义 |
---|---|
? | {0,1}表示最多只出现一次 |
+ | {1,}表示至少出现一次 |
* | {0,}表示出现任意次 |
{n} | 出现n次 |
{n,m} | 出现n到m次 |
{n,} | 至少出现n次 |
注意量词只会作用于紧挨着他的那个字符,并不是整体,因此需要配合分组进行使用
(boy){3}
7:js正则的贪婪模式和非贪婪模式
所谓的贪婪模式就是负责到底,他会根据匹配的规则将要验证的字符串整体的进行验证,所有符合条件规则的字符都会被检测出来。非贪婪模式则反之,有一种得过且过的慵懒,只要有一个符合即可。
通常在正则中的量词后面使用?
切换到非贪婪模式
8:分组
在前面量词的描述中已经接触过分组,其实在后面的或(|)中也需要使用分组来明确正则的匹配范围,因此分组在正则中的作用非常的大。
1):常规写法
var reg = /([a-z]\d){3}/g
定义小写字母后面紧挨着数字的组合字符串出现三次的规则。
如果没有()
量词紧挨着\d
则表示一个小写字母后面紧挨着三个数字。
2):或的表示
var reg = /(Lo|Li)/g
定义全局查询存在Lo或者Li的字符串的规则。
3):反向引用
在分组中通常使用$来代表每一个分组
var str = '2015-11-20'
var reg = /(\d{4})-(\d{2})-(\d{2})/g
str.replace(reg, '$2/$3/$1')
把’2015-11-20’替换成 '11/20/2015’的形式,需要使用分组将其中的数据提取出来,再进行重新的拼接即可。
9:正则表达式的前瞻
在正则表达式中正则表达式的匹配规则是从文本的头部向尾部进行匹配的,因此文本尾部的方向称为前。
而前瞻只是比普通的正则匹配多了一个断言,他在使用正则匹配到符合条件的数据之后,他还要检查一下是否符合断言中的要求。相对于单一的正则匹配,他还多了一个断言检测。同时需要注意的是断言只是起到检测判断作用,并不会进行匹配。
var str = 'a1*34dv4'
var reg = /\w(?=\d)/g // 正向前瞻 匹配一个单词字符,要求他前面必须是一个数字
str.replace(reg, 'X') //结果为:X1*X4dX4
类型 | 符号 |
---|---|
正向前瞻 | exp(?=assert) |
反向前瞻 | exp(?!assert) |
10:正则表达式的属性
正则表达式的属性都是只读的并不能手动进行赋值。
属性 | 意义 |
---|---|
global | 是否全局搜索匹配 |
ignoreCase | 是否忽略大小写 |
multiline | 是否多行匹配搜索 |
lastIndex | 当前表达式匹配内容的最后一个字符的下一个位置 |
source | 正则表达式文本本内容 |
注意:lastIndex属性只在全局匹配时才有效,不是全局匹配是无效的,因为实现全局匹配的前提是他可以在上一个匹配字符的后一个字符位置开始进行检索,因此lastIndex只有在全局匹配时才有意义,当非全局匹配时,他为0表示无效。
前面描述的都是关于正则的一些基础知识,下面的一些方法,才是使用频率较高的一些功法,现在一一罗列进行总结。
1:正则表达式本身的两个方法
1):test方法
RegExp.prototype.test(str)
test方法用于测试字符串中是否有匹配正则规则的字符串,存在返回true,不存在返回false。当正则为全局匹配时,它具有一些隐患,也是由于全局匹配中的lastIndex造成的
var reg1 = /\w/
var reg2 = /\w/g
reg1.test('ab') // 不论执行多次,都会为true
reg2.test('ab')
// 前两次是true,第三次是false。lastIndex指向了最后一个字符所在的位置。
// 这种现象是由于lastIndex导致的,去掉全局匹配即可。
// 非全局状态下,是没有lastIndex属性的
2):exec方法
RegExp.prototype.exce(str)
检测字符串中有没有符合匹配规则的字符串。如果没有返回null,如果有则返回一个结果数组。同时数组还有两个属性: (1)index属性:声明匹配文本的的第一个字符的位置;(2)input属性:存放被检索到的string
非全局调用(适用于只获取第一个匹配结果)
var reg = /\d(\w)\d/
var str = '1z2xx3c4v5'
reg.exec(str)
// 匹配结果为:(多次调用结果还是一样) ['1z2', z]
全局调用(适用于获取所有的匹配结果)
var reg = /\d(\w)\d/g
var str = '1z2xx3c4v5'
reg.exec(str)
//第一次执行:['1z2', z]
//第二次执行:['3c4', c]
//第三次执行: null
2:字符串的方法
方法 1:String.prototype.search(reg)
search方法用于检索字符串中的指定子字符串,或者是检索与正则匹配的字符串,匹配到返回index,匹配不到返回-1; 注意serach方法自动忽略全局匹配g 即他每次查找都是从字符串的起点开始
方法 2: String.prototype.match(reg)
match方法用于检索字符串,以找到一个或者多个与RegExp匹配的文本。
它也分为全局匹配和非全局匹配两种,和exec方法相类似
match的非全局匹配:
1: 只执行依次匹配,如果成功,就返回一个相关数组,如果不成功就返回null
2: 类比正则表达式的方法exec方法
1):返回值是一个数组;
2):数组的第一个元素是第一个匹配的文本,其他项则是当有分组时,存放分组的匹配字符
3): 数组还有两个属性,: index 和 input 和exec是一样的
match的全局匹配:
1:匹配成功返回数组,否则返回null
2:如果返回的是一个数组,不同于非全局的匹配,他没有那么多的额外信息,数组中的每一项都是匹配上的字符,而没有分组的字符
3: 没有index属性 (undefined) 没有input属性 没有lastIndex (为0)
方法 3: String.prototype.split(reg)
例如:split 方法将字符串分割成数组
'a1b2c3d4e'.split(/\d/g) // 结果为:[a,b,c,d,e]
方法 4: String.prototype.replace()
三种替换形式
1: replace(str, replaceStr)
2: replace(reg, replaceStr)
3: replace(reg, function) 用function的返回值作为他的替换结果
function的参数
function会在每一次匹配时被调用到,有四个参数
1):第一个参数是匹配的字符串 match
2):第二个参数乃至后面更多的参数是分组 group : group1 group2… 如果有分组就写,没有分组就不写
3):第三个参数为匹配项在字符串中index
4):第四个参数为原字符串 origin
'a1b2c3d4e5f6'.replace(/(\d)(\w)(\d)/g, function(match, group1, group2,
group3, origin){
console.log(match) // 输出结果为: '1b2' , '3d4', '5f6'
return group1 + group3 // 最后的替换结果为 : 'a12c34e56'
})
学习完教程之后总结出上述所有的内容;篇幅较长,一字一字敲出来,里面内容或有差错,希望有错误或者疑问能够不吝啬的提出来,共同进行探讨。
最后
青春是用来奋斗的,青春也是用来回忆的
希望回忆过往时虽有坎坷与挫折,但也包含成功的自豪喜悦。
愿每一份深情都被真诚相待。