JavaScript学习之正则表达式
正则表达式
如何创建正则表达式
- 字面量创建
var r = /a/;
- 通过构造函数
var r = new RegExp("a");
正则表达式实例属性及方法
- 三个修饰符属性,只读不可修改
RegExp.prototype.ignoreCase
正则表达式是否添加了忽略大小写的修饰符,返回一个布尔值var r = /asd/i; console.log(r.ignoreCase); //true
RegExp.prototype.global
正则表达式是否添加了全局匹配的修饰符,返回一个布尔值var r = /asd/i; console.log(r.global); //true
RegExp.prototype.multiline
正则表达式是否添加了换行的修饰符,返回一个布尔值var r = /asd/m; console.log(r.multiline); //true
RegExp.prototype.lastIndex
返回一个整数,表示正则表达式下一次开始匹配的位置,var s = "wqerqt"; var r = /q/g; console.log(r.lastIndex); //0 console.log(r.test(s)); //true console.log(r.lastIndex); //2 console.log(r.test(s)); //true
- RegExp.prototype.source
返回正则表达式的字符串形式;即不包括首尾的/ - 两个实例方法
RegExp.prototype.test()
作用是否能匹配参数字符串,返回一个布尔值console.log(/as/.test("fdas")); //true console.log(/as/.test("fd")); //false
test()方法在全局g的匹配下,会记录上一次test()后开始的位置,来进行下一次test();
可以这么来理解lastIndex用来指定test()开始的位置,lastIndex只对同一个正则表达式有连续有效的作用,例如重新创建正则表达式,会一直返回true或者falsevar i = 3, r = /as/g; while(i) { console.log(r.test("asd")); i --; } //true false true
下面三种结果相同都是true,相当于新的正则表达式在匹配字符串,只是正则表达式是一样的
var i = 3, while(i) { //r = new RegExp("as","g"); //r = /as/g; console.log(/as/g.test("asd")); i --; } //true true true
所以个人认为在外部定义正则表达式,内部引用会好点
RegExp.prototype.exec()
作用是返回一个数组,成员是匹配成功的字符串,否则返回null
但是数组的长度是组匹配数再加1,例如下面例子的,数组长度只有1var r = /as/g; console.log(r.exec("asdas")); //["as", index: 0, input: "asdas", groups: undefined] console.log(r.exec("asdas")); //["as", index: 3, input: "asdas", groups: undefined] console.log(r.exec("adsd")); //null
返回数组结果还有两个属性:
index:返回匹配时的位置
input:返回参数字符串var r = /as/g; var arr = r.exec("asdas"); console.log(arr.index, arr.input); //0,"asdas" var arr1 = r.exec("asdas"); console.logarr1.index, arr1.input); //3,"asdas"
匹配规则
几个值得记忆的点:
(.):任意字符,除了\r\n\\u2028\u2029的所有单个字符,大于\u0xFFFF的两个字符也不行 [\s\S]与[^]:所有单个字符,包括换行符 o\\bo:不存在这样的单词进行匹配 +:{1,+Infinity},取尽可能大,+?则是取尽可能小,最小为1 *:{0,+Infinity},取尽可能大,*?则是取尽可能小,最小为0 ?:{0,1},取尽可能大,最大为1,??则是取尽可能小,最小为0 [xyz]:单个字符是x或y或z;而[^xyz],则是除了xyz的单个字符
组匹配
就是用来捕获自己想要的值,用来自己进行后续操作
var a = /-(\w)/g; console.log('get-own-property-name'.replace(a,function (match, $1) { return $1.toUpperCase(); })); //getOwnPropertyName
match:匹配成功的字符串
$1:是第一个组匹配的值,例如后面多个括号则是$2$3...
注意组匹配嵌套时的顺序console.log("bc".replace(/((b)c)/g,"$1+$2")); //bc+b
从左开始,而不是从内开始
字符串的match与split在进行组匹配时,是否添加修饰符g结果不一样
console.log("abc".match(/(.)b/g)); //["ab"] console.log("abc".match(/(.)b/)); //(2) ["ab", "a", index: 0, input: "abc", groups: undefined] console.log("abc".split(/(b)/)); // ["a", "b", "c"] console.log("abc".split(/b/)); //["a", "c"]
总结:match方法只要进行了g全局匹配就只会返回最终匹配到的字符串组成的数组;split只要进行了组匹配就会返回捕获的内容
- 非捕获组
用?:
表示;说直白点就是:还是这么匹配但是我不返回括号里的内容,所以我们进行split的组匹配时可以进行修改console.log("abc".split(/(?:b)/)); //["a", "c"]
- 先行断言
用x(?=y)
表示,意思是匹配一个x,x必须在y前面,结果中不返回y - 先行否定断言
用x(?!y)
表示,意思是匹配一个x,x后面不能是y,结果中不返回y - 后行断言
用(?<=y)x
表示,意思是匹配一个x,x前面必须是y,结果中不返回y 后行否定断言
用(?<!=y)x
表示,意思是匹配一个x,x前面不能是y,结果中不返回yconsole.log(/(?<!=b)a/.exec("bcaba")); //["a", index: 2, input: "bcaba", groups: undefined] console.log(/(?<=b)a/.exec("bcaba")); //["a", index: 4, input: "bcaba", groups: undefined]
经典例子:
数字格式化:
var r = /\B(?=((\d{3})+$))/g; console.log('1234567890'.replace(r, '.')); //1.234.567.890 console.log('123'.replace(r, '.')); //123