正则表达式
什么是正则
在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
正则表达式到底能用来做什么
1、测试字符串内的模式。
可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式
2、替换文本。
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
3、基于模式匹配从字符串中提取子字符串。
1 RegExp对象
- 创建的两种方式:
对象字面量 var reg = /is/;
构造函数 var reg = new RegExp('\is'); - 修饰符
g :global 全文搜索
I: ignore case 忽略大小写
m:multiple lines多行搜索
2 元字符
+ * ? $ ^ . | \ ( ) { } [ ]
字符 | 含义 |
---|---|
\t | 水平制表符 |
\v | 垂直制表符 |
\n | 换行符 |
\r | 回车符 |
3 字符类
3-1. 字符组
一般情况下 正则中的一个字符对应一个字符串。
'abcdef'.match(/abc/g); //["abc"]
但是我们有的时候希望匹配某类字符就需要用到字符组(字符类),例如匹配一个字符,它可以是“a”、“b”、“c”其中之一。
'abcdef'.match(/[abc]/g); //["a", "b", "c"]
3-2. 字符范围
连字符-来省略和简写。[0-9] [a-z] [A-Z]
比如[123456abcdefGHIJKLM],可以写成[1-6a-fG-M]
注意 如果要匹配字符串中的"-" ,将"-"写在范围后面即可
'2020-04-04'.replace(/[0-9-]/g,'A');//"AAAAAAAAAA"
3-3 排除字符组
某位字符可以是任何东西,但就不能是"a"、"b"、"c"。[^abc],表示是一个除"a"、"b"、"c"之外的任意一个字符。字符组的第一位放^(脱字符),表示求反的概念。
'ABCDEF0123'.replace(/[^A-D]/g,'0'); //"ABCD000000"
3-4预定义类
字符 | 含义 |
---|---|
\d | [0-9]表示是一位数字。d是digit的简写 |
\D | 就是[^0-9]。表示除数字外的任意字符。 |
\w | 就是[0-9a-zA-Z_]。表示数字、大小写字母和下划线。w是word的简写 |
\W | 是[^0-9a-zA-Z_]。非单词字符 |
\s | 是[ \t\v\n\r\f]。表示空白符。s是space character的简写。 |
\S | 是[^ \t\v\n\r\f]。 非空白符 |
. | 通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。 |
如果要匹配任意字符怎么办?可以使用[\d\D]、[\w\W]、[\s\S]和[^]中任何的一个。
//将数字替换成A
'ABCDEF0123'.replace(/[\d]/g,'A');//"ABCDEFAAAA"
//将非数字替换成X
'ABCDEF0123'.replace(/[\D]/g,'X');//"XXXXXX0123"
4 量词
字符 | 含义 |
---|---|
? | 0次或一次 |
+ | 至少出现一次 |
* | 任意次 |
{n} | 出现n次 |
{n, m} | 出现n到m次。 |
{n, } | 至少出现n次 |
//匹配8位数字的QQ号码
/^\d{8}$/g.test('12345678'); //true
//匹配1开头11位数字的手机号码
/^1\d{10}$/g.test('12345678910'); //true
//匹配银行卡号是14~18位的数字:
/^\d{14,18}$/g.test('12345678901234567'); //true
//匹配以a开头的,0个或多个b结尾的字符串
/^0b*$/g.test('0bbbb'); //true
贪婪匹配和惰性匹配
正则是贪婪模式,会尽可能多的匹配。
var regex = /\d{2,5}/g;
var string = "123456";
console.log( string.match(regex) ); //["12345"]
而惰性匹配,就是尽可能少的匹配,通过在量词后面加个问号就能实现惰性匹配,因此所有惰性匹配情形如下:
var regex = /\d{2,5}?/g;
var string = "123456";
console.log( string.match(regex) ); //["12", "34", "56"]
5边界
字符 | 含义 |
---|---|
^ | 匹配开头,在多行匹配中匹配行开头 |
$ | 匹配结尾,在多行匹配中匹配行结尾 |
\b | boundary ,单词边界 |
\B | \B就是\b的反面的意思,非单词边界 |
(?=p) | 正向先行断言,也叫正向前瞻。其中p是一个子模式,即p前面的位置 |
(?!p) | 负向先行断言,也叫负向前瞻。即p后面的位置 |
^和&
//比如我们把字符串的开头和结尾用"#"替换
var result = "hello".replace(/^|$/g, '#');
console.log(result); // "#hello#"
\b和\B
var result = "[JS] Lesson_01.mp4".replace(/\b/g, '#');
console.log(result); //"[#JS#] #Lesson_01#.#mp4#"
\b是单词边界,具体就是\w和\W之间的位置,也包括\w和^之间的位置,也包括\w和$之间的位置。
首先,我们知道,\w是字符组[0-9a-zA-Z_]的简写形式,即\w是字母数字或者下划线的中任何一个字符。
而\W是排除字符组[^0-9a-zA-Z_]的简写形式,即\W是\w以外的任何一个字符。
此时我们可以看看"[#JS#] #Lesson_01#.#mp4#"中的每一个"#",是怎么来的。
1.第一个"#",两边是"["与"J",是\W和\w之间的位置。
2.第二个"#",两边是"S"与"]",也就是\w和\W之间的位置。
3.第三个"#",两边是空格与"L",也就是\W和\w之间的位置。
4.第四个"#",两边是"1"与".",也就是\w和\W之间的位置。
5.第五个"#",两边是"."与"m",也就是\W和\w之间的位置。
6.第六个"#",其对应的位置是结尾,但其前面的字符"4"是\w,即\w和$之间的位置。
\B就是\b的反面的意思,非单词边界。例如在字符串中所有位置中,扣掉\b,剩下的都是\B的。
再举个例子,要将"This is an apple."中的is替换成"X"。
'This is an apple'.replace(/is/,'X');//"ThX is an apple"
这样会将单词中的is 一起匹配替换掉,如果指向匹配 单词"is"
'This is an apple'.replace(/\bis\b/,'X');//"This X an apple"
如果只想讲"This"中的"is"替换掉
'This is an apple'.replace(/\Bis/,'X');//"ThX is an apple"
(?=p)和(?!p)
(?=X),表示前面是'X'字符的位置,(?!X)表示前面不是'X'字符位置例如:
'ABCD'.replace(/(?=D)/,"X");//"ABCXD"
'ABCD'.replace(/(?!B)/g,"X");//"XABXCXDX"
*注意正则表达式从文本头部向尾部开始解析,文本尾部方向称为前。前瞻就是在正则表达式匹配到规则的时候,向前检查是否符合断言。(和正常理解的前后不同,要注意一下)
6正则中的括号
分组
量词是作用于紧挨着的字符,例如/^ab+$/ 会匹配到'abbb' 而不是'abab'
如果我们想匹配到'abab' 就要用/^(ab)+$/
/^ab+$/.test('abab'); //false
/^ab+$/.test('abbb'); //false
/^(ab)+$/.test('abab'); //true
/^(ab)+$/.test('abbb'); //false
分支结构
或'|': 多个分支可以走任意一个 (aaa | bbb)
'JasperDasper'.replace(/(J|D)asper/g,'X'); //"XX"
如果不加括号则是匹配到'|' 前后的所有字符
var regex = /^I love (JavaScript|Regular Expression)$/;
console.log( regex.test("I love JavaScript") );//true
console.log( regex.test("I love Regular Expression") );//true
引用
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
string.replace(regex,'$1/$2/$3'); //"2017/06/12"
string.replace(regex,'$2/$3/$1'); //"06/12/2017"
上例中,我们用()将表达式分为了三组,在replace方法中$1、$2、$3指代相应的分组。
反向引用
正则本身里引用分组。但只能引用之前出现的分组,即反向引用。
例如需要验证"2017-06-12","2017/06/12" "2017.06.12" "2016-06/12",这几种格式的日期,我们可以用/\d{4}(-|/|.)\d{2}\1\d{2}/,其中(-|/|.)是一个分组,而\1就是引用的该分组的内容
var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // false
非捕获分组
也称为忽略分组,不希望捕获某些分组时,只需要在分组内加上?:即可
例如 (?:Byron).(ok) 在引用\1时 ,会引用到(ok),分组 (?:Byron).已被忽略。
常用方法
属性
global:是否全文搜索,默认false
ignore case:是否大小写敏感,默认false
multiline:多行搜索,默认值是false
lastIndex:是当前表达式匹配内容的最后一个字符的下一个位置
source:正则表达式的文本字符串
var reg1 = /\w/;
var reg2 = /\w/gim;
reg1.global;//false
reg2.global://true
reg1.ignoreCase://false
reg2.ignoreCase:;//true
reg1.multiline;//false
reg2.multiline;//true
reg1.lastIndex;//0
reg2.lastIndex;//0
reg1.source;//"\w"
reg2.source;//"\w"
在RegExp对象中:
1:test
定义:检测一个字符串是否匹配某个模式。
/(abc)+/.test("abc123") // true
2:exec
定义:检索字符串中的正则表达式的匹配。
如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。
/([a-z])+(\d)+/.exec("abc123abc123abc123") // ["abc123", "c", "3", index: 0, input: "abc123abc123abc123", groups: undefined]
非全局匹配:
第 0 个元素是与正则表达式相匹配的文本,
第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本
第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本
index 属性声明的是匹配文本的第一个字符的位置。
input 属性则存放的是被检索的字符串 string。
var str = 'asd1adf2ad3sdc4'
var reg2 = /\d/g;
reg2.exec(str);//["1", index: 3, input: "asd1adf2ad3sdc4", groups: undefined]
reg2.exec(str);//["2", index: 7, input: "asd1adf2ad3sdc4", groups: undefined]
reg2.lastIndex;//8
reg2.lastIndex = 1;
reg2.exec(str);//["1", index: 3, input: "asd1adf2ad3sdc4", groups: undefined]
全局匹配:
全局匹配模式下,此方法返回值依然是一个数组。和非全局匹配模式下完全一样。
lastIndex属性用来规定正则表达式在字符串中开始检索的位置。
exec方法可以与lastIndex属性配合使用。
如果正则表达式匹配失败,那么lastIndex属性被重置为0。
在String对象中:
1:search
定义:检索字符串中与指定的子字符串或正则表达式相匹配的子字符串。
其他说明:该方法将忽略"g"标志和正则对象的lastIndex属性(即总是从开头找起),返回找到的第一个字符的位置,如果未找到返回-1。
2:match
定义:在字符串内查找一个或多个与正则表达式匹配的字符串,返回一个对象。
非全局调用,返回一个对象,和exec非全局搜索时一样。
全局调用时,返回的数组的内容与前者大不相同,它的数组元素中存放的是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。
var str="1 plus 2 equal 3"
console.log(str.match(/\d+/g));//["1", "2", "3"]
3:replace(yourRegexpOrString,placementString);
定义:用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
stringObject.replace(regexp/substr,replacement)
replacement 可以是字符串,也可以是函数。如果它是字符串,那么每个匹配都将由字符串替换。但是 replacement 中的 1、$2、 与 regexp 匹配的子表达式的文本。
var string = 'className';
string.replace(/[A-Z]/g,'x');//"classxame"
var string 1 = 'world, hello';
string1.replace(/(\w+)(?:\W*)(\w+)/,'$2 $1');//"hello world"
var name = 'aaa bbb ccc';
name.replace(/\b\w+\b/g, function(word){
return word.substring(0,1).toUpperCase()+word.substring(1);
});//"Aaa Bbb Ccc"
4:split
定义:把一个字符串分割成字符串值的数组。
是arr.join(separatorString)反操作,如果传入"",则每个字符都将会被分隔到数组。howMany指定返回数组的个数。
var a= 'banana';
a.split(/a/);//["b", "n", "n", ""]
如果正则表达式包含子表达式,那么返回的数组中包括与这些子表达式匹配的字串。
var a= 'banana';
a.split(/b(a)/);//["", "a", "nana"]
a.split(/a/);//["b", "n", "n", ""]
a.split(/a(n)/);//["b", "n", "", "n", "a"]