正则表达式,又称为规则表达式,英文叫 Regular Expression,在代码中 通常简写为regexp,大量用在文本的检索和替换。大部分高级语言都是支持正则的。今天我们以javacript 里的正则来展开学习。
一:简单的例子
1.比如我们需要判断一个字符串里面都是数值,我们可以这样写:
var reg = /^\d+$/;
reg.test('1232323'); // true
比如我们要匹配出字符串中的数字,我们可以这样写:
var match = /\d+/g.exec('1abc33');// 匹配数字
// ["1", index: 0, input: "1abc33", groups: undefined]
二:基础知识
- 如何定义一个正则表达式
/正则表达式的主体表达式/修饰符
var reg = /abc/;
var reg = RegExp('abc')
var reg1 = new RegExp('abc');
正如字符串,数值的定义方法一样,正则的定义也分为字面量,和构造函数的定义方法
- 正则表达式的字符匹配
符号 | 作用 | 示例 |
---|---|---|
. | 匹配任意单个字符,行结束符号除外 | 比如:/./.test(‘a’)//true |
\d | 匹配任意阿拉伯数字 | 比如:/\d/.test(‘1’)//true |
\D | 匹配任意不是阿拉伯数字 | 比如:/\D/.test(‘s’)//true |
\w | 匹配阿拉伯数字字母和下划线 | 比如:/\w/.test(’_’)//true |
\W | 匹配不是\w能匹配的字符 | 比如:/\W/.test(’_’)//false |
\s | 匹配空格、制表符、换行符、换页符、等空白字符 | 比如:/\s/.test(’ ')//true |
\S | 匹配任意不是\s能匹配的字符 | 比如:/\S/.test(’ ')//false |
\t | 匹配水平制表符号 | |
\r | 匹配回车符号 | |
\n | 匹配换行符号 | |
\v | 垂直制表符号 |
- 正则表达式里的元字符
元字符代表符号本身不表示他本身的含义:例如上面的点号,并不是表示匹配一个点,而是正则用来匹配的一个符号;我们可以理解为正则里的关键字
符号 | 作用 | 示例 |
---|---|---|
^ | 表示一个字符串的开头位置 | 比如:/^\d/.test(‘s1’)//false |
$ | 表示一个字符串的结束位置 | 比如:/\d$/.test(‘1s’)//false |
. | 匹配任意单个字符,行结束符号除外 | 比如:/./.test(‘a’)//true |
* | 表示匹配0个或者多个字符 | 比如:/\d*/.test(‘1’)//true |
+ | 表示匹配1个或者多个字符 | 比如:/\d+/.test(‘12’)//true |
? | 表示匹配0个或者1个字符 | 比如:/\d*/.test(‘1’)//true |
() | 表示一个匹配分组 | 比如:/(\d+)/.test(‘1’)//true |
[] | 表示一个匹配的取值范围 | 比如:/[0-9a-z]/.test(‘1’)//true |
^ | 表示一个匹配的取值范围 | 比如:/[0-9a-z]/.test(‘1’)//true |
| | 表示多个匹配条件只要符合一个即可,类似于or | 比如:/\d|\w/.test(’_’)//true |
\ | 转义字符,很多特殊的匹配符号需要用到,加了斜杠就说明字符不代表他本身的含义了 | 比如:\d \s \w |
- flags修饰符
flgas修饰符号是设置正则匹配的模式,一次可以设置多个模式
写法:
/\d/i
new RegExp('\d', 'i')
new RegExp('\d', 'im')
详细说明:
i 表示匹配的时候忽略大小写
m 表示多行匹配模式
g 表示全局匹配
y 表示粘性匹配
s 表示点符号能够匹配行结束符号
u 表示以unicode的编码方式匹配字符
示例:
// flag:i
/[a-z]/.test('A');//false
/[a-z]/i.test('A');//true
// flag:m
/^abc$/.test(`1232343
abc`) // false
/^abc$/m.test(`1232343
abc`) // true
// flag:g
'12abc12'.match(/\d+/g)//["12", "12"]
'12abc12'.match(/\d+/) //["12", index: 0, input: "12abc12", groups: undefined]
// 全局模式下,会从0开始匹配,向后尝试,直到字符中所有的可能都匹配结束
var reg = /\d-/g;var str='1-abc1-';
reg.exec(str);
console.log(reg.lastIndex) //2
reg.exec(str);
console.log(reg.lastIndex) // 7
// 非全局模式下,每次匹配都是从0开始
var reg = /\d-/;var str='1-abc1-';
reg.exec(str);
console.log(reg.lastIndex) //0
reg.exec(str);
console.log(reg.lastIndex) //0
// flag:y
var reg = /\d-/y;var str='1-de1-';
reg.exec(str);
console.log(reg.lastIndex)//2
reg.exec(str);// 匹配失败了,因为y导致了正则会从索引2的位置开始匹配,匹配不到就结束。
console.log(reg.lastIndex)//0
//改成这样:
var reg = /\d-/yg;var str='1-1-';
reg.exec(str);
console.log(reg.lastIndex) //2
reg.exec(str); // 匹配成功,因为从第2个索引位置开始的1-符合正则
console.log(reg.lastIndex)//4
//所以粘连总结来说就是下一个匹配成功的起使位置必须是紧跟这上一个匹配的结束位置
// flgs:s
/./.test('\n') // false
/./s.test('\n') // true
- 集合
[abc] // 表示匹配满足abc中的任意一个
[\w] // 表示匹配满足\w能匹配的字符中的任意一个:数字字母下划线
[a-z] // 表示匹配a和z之间26个字母的任意一个
[a-z0-9] // 表示匹配a到z 0到9 中字符的任意一个
[^0-9] // 取反模式,上述的几种情况前面只要加上^ 就表示不符合后面模式里的任意一个即可,这个要和代表字符串起点的^的用法区别开
示例:
/[a-z]/.test('s')// true
/[^a-z]/.test('s')// false
/[^a-z]/.test('1')// true
/[0-9a-z_]/.test('_')// true
/[\w]/.test('_')// true
- 边界
^ //表示字符的起使位置
$ // 表示字符的结束位置
\b // 匹配单词边界
\B // 匹配非单词边界
示例:
// 表示以数字开头,数字结尾的字符串
/^\d+$/.test('12333')//true
// 匹配独立存在abc,即两边没有任何字符,
/\babc\b/.exec('dabc abc')//["abc", index: 5, input: "dabc abc", groups: undefined]
// 匹配前面不是单词边界,后面是的abc
/\Babc\b/.exec('dabc abc')//["abc", index: 1, input: "dabc abc", groups: undefined]
- 量词
?// 匹配0个或者1个
+ // 匹配1个或者多个
* // 匹配0个或者多个
{m}// 匹配m个,例如\d{2} 匹配两个数字
{m,n}// 匹配m到n范围内个数的字符,包含m和n
{m,}// 匹配大于等于m个的字符
示例:
/a\d?/.test('a')// true
/a\d?/.test('a1')// true
/a\d+/.test('a')// false
/a\d+/.test('a1')// true
/a\d+/.test('a123')// true
/a\d*/.test('a')// true
/a\d*/.test('a1')// true
/a\d*/.test('a123')// true
/a\d{2}/.test('a1')// false
/a\d{2}/.test('a12')// true
/a\d{2,3}/.test('a12')// true
/a\d{2,3}/.test('a123')// true
/a\d{2,3}/.test('a1234')// false
/a\d{2,}/.test('a1234')// true
- 分组
通过括号的方式对匹配的内容进行分组,方便更细化的处理字符串
(abc) // 捕获分组,分组信息会存储在正则对象中
(?:abc) //非捕获型的分组,不存储分组信息
/(?<g1>\d)// 命名捕获分组
// 返回的类数组第二个元素就是分组的内容-
var reg = /\d(-)/g;var str='1-abc1-';//["1-", "-", index: 0, input: "1-abc1-", groups: undefined]
// 采用非捕获分组,只返回了匹配的全部内容,没有返回分组部分的内容
var reg = /\d(?:-)/g;var str='1-abc1-';
reg.exec(str);//["1-", index: 0, input: "1-abc1-", groups: undefined]
//命名捕获分组
/(?<a>\d)/.exec('12')
/** 返回结果
[
0: "1"
1: "1"
groups: {a: "1"}
index: 0
input: "12"
length: 2
__proto__: Array(0)
]
**/
- 贪婪模式和非贪婪模式
贪婪模式:尽可能多的匹配
非贪婪模式(懒惰模式):尽可能少的匹配
// 贪婪
/\d+/.exec('123232323') // 123232323
// 懒惰
/\d+?/.exec('123232323') // 1
贪婪模式:
+
*
{m,n}
{m,}
?
懒惰模式(在贪婪模式后面再加个问好就可以变为懒惰模式)
+?
*?
{m,n}?
{m,}?
??
- 断言
- 先行肯定断言 (?=abc)
- 先行否定断言 (?!abc)
- 后行肯定断言 (?<=abc)
- 后行否定断言 (?<!abc)
例如:
// 匹配后面紧跟为数字的abc
/abc(?=\d)/.exec('abcs abc1e')
// ["abc", index: 5, input: "abcs abc1e", groups: undefined]
// 匹配后面紧跟的不是数字的abc
/abc(?!\d)/.exec('abcs abc1e')
// ["abc", index: 0, input: "abcs abc1e", groups: undefined]
// 匹配前面是数字的字符串的abc
/(?<=\d)abc/.exec('1abc sabc') // ["abc", index: 1, input: "1abc sabc", groups: undefined]
// 匹配前面不是数字的字符串abc
/(?<!\d)abc/.exec('1abc sabc')
["abc", index: 6, input: "1abc sabc", groups: undefined]
三:正则对象
- RegExp 静态属性
RegExp.$1-$9 匹配最近一次正则匹配的9个分组
RegExp.input RegExp.$_最近一次参与匹配的字符串
RegExp.lastMatch RegExp['$&'] 最近一次匹配到的字符
RegExp.lastParen RegExp['$+'] 匹配到最后一个子串
RegExp.leftContext RegExp["$`"] 被匹配到的字符的左侧的字符串
RegExp.rightContext RegExp["$'"] 被匹配到的字符的右侧的字符串
- RegExp 实例属性
lastIndex 上一次匹配到的位置
flags 匹配模式
source 正则字面量
dotAll 是否开启dotAll 模式,也就是. 可以匹配各种行结束符号
global 是否开启全局模式
ignoreCase 是否忽略大小写
multiline 是否开始多行匹配模式
sticky 是否启动粘性匹配模式
unicode 是否使用unicode编码匹配模式
四:常见的使用Api
- exec
//提取符合正则的字符串
/\d+/.exec('123abc456')
//["123", index: 0, input: "123abc456", groups: undefined]
// 全局模式提取符合正则的字符串,每执行一次,lastIndex会从上一次匹配结束的位置开始继续匹配
var reg = /\d+/g;
var str = '123abc456'
var r1 = reg.exec(str)//["123", index: 0, input: "123abc456", groups: undefined]
var r2 = reg.exec(str)//["456", index: 6, input: "123abc456", groups: undefined]
console.log(reg.lastIndex)//9
- match
这是字符串对象提供的api
// 全局模式下,返回包含所有能够匹配的内容数组
'123abc456'.match(/\d+/g) // ["123", "456"]
// 非全局模式下,返回一个类数组,里面包含[匹配到的内容,...分组的内容,其他正则实例属性]
'123ab5c456'.match(/(\d([a-z]))/) //["3a", "3a", "a", index: 2, input: "123ab5c456", groups: undefined]
- search
这是字符串对象提供的api
// 找到符合正则的字符串的启使位置
'accc1'.search(/\d/) //4
- test
// 检测字符串里有没有数字,返回布尔类型
/\d/.test('1221212') // true
- split
字符串对象提供的api
// 按照数字截取字符串
'abc12eaber563ss'.split(/\d+/) // ["abc", "eaber", "ss"]
- replace
字符串对象提供的api
// 将字符串中的数字替换成空字符
'abc123'.replace(/\d+/,'') // abc
// 回调函数的写法,将字符串中匹配到的内容替换成callback返回的内容
'abc123'.replace(/\d+/,function(a){
return '['+a+']';
});//abc[123]
'abc123'.replace(/([a-z])(\d)/,'$1-$2') //abc-123
其他一些用法
// \1 匹配和第一个分组相同的内容,
/(\d)\1/.exec('1222') // 提取出了 2) ["22", "2", index: 1, input: "1222", groups: undefined]