1.关于正则表达式的使用
可以去这个网站上将正则表达式表示为形象化的图像
2.正则表达式研究
2.1 RegExp对象
Javascript通过内置对象RegExp支持正则表达式
有两种方法实例化RegExp对象
字面量
构造函数
字面量的方式
var reg=/ is /g ;
如下代码所示
var reg=/is/;
'He is a boy.This is a dog. Where is she?'.replace(reg,'IS')
//"He IS a boy.This is a dog. Where is she?"
//只替换了第一个正则匹配的字符
var reg=/is/g;
'He is a boy.This is a dog. Where is she?'.replace(reg,'IS')
//"He IS a boy.This IS a dog. Where IS she?"
//加上g之后,替换了所有正则匹配到的字符
构造函数
var reg=new RegExp('is','g');
构造函数接收2个参数,第1个是正则表达式的文本(这里的要写2次,是因为是特殊字符,如果想使用的话,需要转义),第2个参数是字符串标志
var reg=new RegExp('\bis\b')
undefined
'He is a boy.This is a dog. Where is she?'.replace(reg,'IS')
//"He IS a boy.This is a dog. Where is she?"
//只替换了第一个正则匹配的字符
var reg=new RegExp('\bis\b','g')
undefined
'He is a boy.This is a dog. Where is she?'.replace(reg,'IS')
"He IS a boy.This IS a dog. Where IS she?"
//加上g之后,替换了所有正则匹配到的字符
修饰符
g: global 全文搜索,不添加,搜索到第一个匹配停止
i: ignore case忽略大小写,默认大小写敏感,如下代码所示
m:multiple lines多行搜索
'He is a boy.Is he'.replace(/is/g,'0')
//"He 0 a boy.Is he"
'He is a boy.Is he'.replace(/is/gi,'0')
//"He 0 a boy.0 he"
2.2 元字符
正则表达式由两种基本字符类型组成:
原义文本字符(例如abc,a)
元字符 :是在正则表达式中有特殊含义的非字母字符(比如表示单词边界)
- ? $ ^ . | () {} [] (水平制表符) v (垂直制表符) (换行符) (回车符) (空字符)f(换页符) cX(与X对应的控制字符 Ctrl+X)
2.3 字符类
一般情况下正则表达式一个字符对应字符串一个字符
比如表达式ab 的含义是匹配(ab水平制表符)的字符串
元字符[]
但是我们不希望匹配某个字符,还是希望匹配某类字符,这时候怎么处理呢?比如要匹配abc特征的字符
我们可以使用元字符[] 来构建一个简单的类
所谓类是指符合某些特性的对象,一个泛指,而不是特指某个字符
表达式[abc]把字符a或b或c归为一类,表达式可以匹配这类的字符,[abc]的含义就是匹配abc中的一个
如下代码:[abc]会匹配一个abc中的一个字符,而不是所有的abc字符
'a1b2c3d4'.replace(/[abc]/g,'X')
"X1X2X3d4"
'abc1b2c3d4'.replace(/[abc]/g,'X')
"XXX1X2X3d4"
字符类取反
使用元字符^创建反向类/负向类
反向类的意思是不属于某类的内容
表达式[^abc]表示不是字符a或b或c的内容
如下代码
'abc1b2c3d4'.replace(/[^abc]/g,'X')
//"abcXbXcXXX"
2.4 范围类
使用字符串匹配数字[0123456789]
正则表达式提供了范围类
所以可以使用[a-z]来连接两个字符表示从a到z的任意字符
这是个闭区间,也就是包含a和z本身
如下代码:
'abc1b2c3d4z9'.replace(/[a-z]/g,'Q')
//"QQQ1Q2Q3Q4Q9"
在[]组成的类内部是可以连写的 [a-zA-Z],如下:
'abc1b2c3d4z9AEEEE'.replace(/[a-zA-Z]/g,'Q')
//"QQQ1Q2Q3Q4Q9QQQQQ"
如果先要匹配-呢
'2016-09-12'.replace(/[0-9]/g,'A')
//"AAAA-AA-AA"
'2016-09-12'.replace(/[0-9-]/g,'A')
//"AAAAAAAAAA"
2.5 JS预定义类及边界
正则表达式提供预定义类来匹配常见的字符类
匹配一个ab+数字+任意字符的字符串
ab[0-9][^
]
abd.
边界
如下代码:
'This is a boy'.replace(/is/g,'IS')
"This IS a boy"
'This is a boy'.replace(/Bis/g,'IS')
"ThIS is a boy"
^不在[]表示以...开始,在[]里面表示取反
'@122@abc@'.replace(/@./g,'Q')
//"Q22Qbc@"
'@122@abc@'.replace(/^@./g,'Q')
//"Q22@abc@",匹配开头的
'@122@abc@'.replace(/.@$/g,'Q')
//"@122@abQ",匹配结尾的
'@122@abc@'.replace(/.@$/gm,'Q')
m可以用来匹配换行的字符串
2.6 量词
我们希望匹配一个连续出现20次数字的字符串
dddddddddddddddddd
字符 | 描述 |
---|---|
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 |
? | 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 |
d{20}
表示匹配一个连续出现20次数字的字符串
2.7 JS正则贪婪模式与非贪婪模式
用d{3,6}来匹配12345678的字符串,得到结果是什么呢?是匹配3次,还是6次,还是4,5次呢
正则表达式在匹配的时候会尽可能多地匹配,直到匹配失败,这是一种贪婪模式
'12345678'.replace(/d{3,5}/,'Q')
//"Q678"
如果让正则表达式尽可能少的匹配,也就是说一旦成功匹配不再继续尝试,就是非贪婪模式
做法很简单,在量词后加上?即可
。如下代码,匹配最小匹配到的就可以了。
'12345678'.match(/d{3,5}?/g)
//(2) ["123", "456"]
'123456789'.match(/d{3,5}?/g)
//(3) ["123", "456", "789"]
'12345678'.replace(/d{3,5}?/g,'X')
//"XX78"
2.8 分组
匹配字符串Byron连续出现3次的场景
Byron{3}表示n重复3次,前面的Byro并没有重复,量词作用于紧挨着的那个单词
使用() 可以达到分组的功能,使量词作用于分组,上面的需求可以用下面来表示
(Byron){3}
'a1b2c3d4'.replace(/[a-z]d{3}/g,'X')
//"a1b2c3d4"
'a1b2c3d4'.replace(/([a-z]d){3}/g,'X')
//"Xd4"
或
使用|可以达到或的效果,Bycon|Casper
'ByronCasper'.replace(/Byron|Casper/g,'X')
//"XX"
'ByronsperByronCasper'.replace(/Byr(on|Ca)sper/g,'X')
"XByronCasper"
'ByronsperByrCasper'.replace(/Byr(on|Ca)sper/g,'X')
//"XX"
反向引用
2015-12-25=>12/25/2015,使用$来获取分组的内容,如果没有分组的话,将其解读为字符串
'2015-12-25'.replace(/(d{4})-(d{2})-(d{2})/g,'$2$3$1')
//"12252015"
'2015-12-25'.replace(/(d{4})-(d{2})-(d{2})/g,'$1')
//"2015"
'2015-12-25'.replace(/(d{4})-(d{2})-(d{2})/g,'$2')
//"12"
'2015-12-25'.replace(/(d{4})-(d{2})-(d{2})/g,'$3')
//"25"
'2015-12-25'.replace(/(d{4})-(d{2})-(d{2})/g,'$2/$3/$1')
//"12/25/2015"
忽略分组
不希望捕获某些分组,只需要在分组内加上 ?: 就可以,如下所示
(?: Byron) .(ok)
2.9 前瞻
正则表达式从文本头部向尾部开始解析,文本尾部方向,成为“前”
前瞻就是在正则表达式匹配到规则的时候,向前检查是否符合断言,后顾/后瞻方向相反。
Javacript并不支持后顾
符合和不符合特定断言成为肯定/正向 匹配和否定/负向匹配
w(?=d) 表示匹配到符合单词的而且还要向后面看看是不是数字,匹配部分只算到匹配到的单词部分,不算后面看的部分
'a2*3'.replace(/w(?=d)/g,'X')
//"X2*3"
'a2*34V8'.replace(/w(?=d)/g,'X')
//"X2*X4X8"
'a2*34vv'.replace(/w(?=d)/g,'X')
//"X2*X4vv"
'a2*34vv'.replace(/w(?!d)/g,'X')
//"aX*3XXX"
2.10 JS对象属性
global: 是否 全文搜索,默认false
ignore case:是否大小写敏感,默认是false
multiline:多行搜索,默认是false
lastIndex:是当前表达式匹配内容的最后一个字符的下一个位置
source:正则表达式的文本字符串
var reg=/w/;
reg.global
//false
reg.ignoreCase
//false
reg.multiline
//false
var reg2=/w/gim;
reg2.global
//true
reg2.ignoreCase
//true
reg2.multiline
//true
reg.source
//"w"
reg2.source
//"w"
这几个属性是只读的,不可以手动修改的
2.11 test和exec方法
RegExp.prototype.test(str)
用于测试字符串参数中是否存在匹配正则表达式模式的字符串
如果存在返回true,否则返回false
var reg=/w/;
reg.test('a')
true
reg.test('$')
false
var reg2=/w/gim;
reg2.test('ab')
true
reg2.lastIndex
1
reg2.test('ab')
true
reg2.lastIndex
2
reg2.test('ab')
false
reg2.lastIndex
0
如上代码所示,当使用g的修饰符时候,使用test方法有时返回true,有时返回false,这是因为执行的时候lastIndex会发生变化。
上面的test方法只知道lastIndex,如果想知道是从哪个字符开始匹配的,要用到
RegExp.prototype.exec(str)
使用正则表达式模式对字符串执行搜索,并将更新全局RegExp对象的属性以反映匹配结果
如果没有匹配的文本则返回null,否则返回一个结果数组
--index 声明匹配文本的第一个字符的位置
--input存放被检索的字符串string
非全局调用
调用非全局的RegExp对象的exec()时,返回数组
第一个元素是与正则表达式相匹配的文本
第2个元素是与RegExpObject的第一个子表达式相匹配的文本(如果有的话)
第3个元素是与RegExpObject的第二个子表达式相匹配的文本(如果有的话)
String.prototype.search(reg)
search方法用于 检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串
方法返回第一个匹配结果index,查找不到返回-1
search方法不执行全局匹配,它将忽略标志g,并且总是从字符串的开始进行检索
'a1b2c3d1'.search('1')
1
'a1b2c3d1'.search('10')
-1
'a1b2c3d1'.search(1)
1
'a1b2c3d1'.search(/1/)
搜索数字也可以得到结果,因为会将数字转换为正则
String.prototype.match(reg)
match()方法将检索字符串,以找到一个或多个与regexp匹配的文本
regexp是否具有标志g对结果影响很大
非全局调用的情况
- 如果regexp没有标志g,那么match()方法就只能在字符串中执行一次匹配
- 如果没有找到任何匹配的文本,则返回null
- 否则它将返回一个数组,其中存放了与它找到的匹配文本有关的信息
- 返回数组的第一个元素存放的是匹配文本,而其余的元素存放的是与正则 表达式的子表达式匹配的文本
除了常规的数组元素以外,返回的数组还含有2个对象属性
index声明匹配文本的起始字符在字符串的位置
input声明对StringObject的引用
全局调用的情况
如果regexp具有标志g则match()方法将执行全局检索,找到字符串中的所有匹配子字符串
没有找到任何匹配的子串,则返回null
如果找到了一个或多个匹配子串,则返回一个数组
数组元素中存放的是字符串中所有的匹配子串,而且也没有index属性或input属性
String.prototype.split(reg)
我们经常使用split方法把字符串分割为字符数组
在一些复杂的分割情况下我们可以使用正则表达式解决,如下代码
'a,b,c,d'.split(',')
(4) ["a", "b", "c", "d"]0: "a"1: "b"2: "c"3: "d"length: 4__proto__: Array(0)
'a1b2c3d'.split(/d/)
(4) ["a", "b", "c", "d"]
String.prototype.replace
String.prototype.replace(str,replaceStr)
String.prototype.replace(reg,replaceStr)
String.prototype.replace(reg,function)
上面2种方式,上面的例子中已经有体现了,看最后一个方式
如果想把'a1b2c3d4'=>'a2b3c4d5',用什么方式呢
function会在每次匹配替换的时候调用,有四个参数:
1.匹配字符串
2.正则表达式分组内容,没有分组则没有该参数
3.匹配项在字符串中的index
4.原字符串
如下代码
'a1b2c3d4e5'.replace(/d/g,function(match,index,origin){
console.log(index);
return parseInt(match)+1;
})
//1
//3
//5
//7
//9
"a2b3c4d5e6"
还可以用下面的分组参数
'a1b2c3d4e5'.replace(/(d)(w)(d)/g,function(match,group1,group2,group3,index,origin){
console.log(match);
return group1+group3;
});
//1b2
//3d4
"a12c34e5"