体验正则表达式的能力
在一堆字符串中,获取里面的数字。
普通代码
let hd = 'jianyidexiaoxietongzhi2548564'; let numstr = [...hd].filter(item => !Number.isNaN(parseInt(item))); console.log(numstr);
正则表达式代码
let hd = 'jianyidexiaoxietongzhi2548564'; console.log(hd.match(/\d/g));
创建正则表达式
使用字面量的方式
优点
方便快捷,便于书写使用。
//建立一个字符串变量 let hd = 'jianyidexiaoxietongzhi'; //字面量创建正则 let rex = /j/; //test 是一个正则方法,判断正则表达式是否能在字符串中匹配到内容,返回值是布尔值 console.log(rex.test(hd));
缺点
正则表达式只可以匹配表面的字符串。获取不到变量
//建立一个字符串变量 let hd = 'jianyidexiaoxietongzhi123'; //字面量创建正则 let j = '1'; let rex = /j/; //match 是一个字符串方法,前面的字符串包不包含扩内的的正则表达式,包含的话则返回值,没有的话返回null console.log(hd.match(rex));
获取到的是变量j字符串,而不是变量j里的具体内容。
使用eval方法和模板字符串解决问题不大
//建立一个字符串变量 let hd = 'jianyidexiaoxietongzhi123'; //字面量创建正则 let j = '1'; let rex = `/${j}/`; //使用模板字符串获得变量的值,在使用eval获取返回值 console.log(hd.match(eval(rex)));
使用对象创建正则表达式
//不需要写/ /直接写正则内容即可 let hd = 'jianyidexiaoxietongzhi' //使用对象的方式创建正则 let reg = new RegExp('d', 'g'); console.log(hd.match(reg));
对象创建的正则也可以直接识别变量,
注意使用对象创建的时候 写相关标识符的时候比如\d需要写成\ \d 写两个\才有效果,字符串里面一个\只代表一个普通文本。
let hd = 'jianyidexiaoxietongzhi' //使用对象的方式创建正则 let d = 'j' let reg = new RegExp(d, 'g'); console.log(hd.match(reg));
方法
正则表达式的两个方法
test
判断正则表达式中的内容是否包含在字符串中,无论在什么位置,返回值是逻辑值,true或false
let str = /xiaoxie/; console.log(str.test('jianyidexiaoxietongzhi'));
exec
从字符串中获取符合正则表达式规则的部分片段,返回值是捕获的字符串等相关内容,没有捕获到则返回null。
没有捕获到
let str = /xiaoxie/; console.log(str.exec('jianyidexaoxietongzhi'));
捕获到
let str = /xiaoxie/; console.log(str.exec('jianyidexiaoxietongzhi'));
返回捕获到的字符串 以及字符串开始的索引位置,和原字符串,只会匹配到第一次符合规则的字符串。
特殊字符
基础元字符
\s
表示匹配一个空格字符,等价于‘ ’。
let rex = /\s/ console.log(rex.test(' d'));
\S
表示匹配一个非空格字符,字符串里面需要至少一个非空格字符
let rex = /\S/; console.log(rex.test(' x'));
\t
表示匹配一个tab字符,字符串里面需要至少一个tab字符,
let rex = /\t/; //两个空格 console.log(rex.test(' ')); //一个tab建 console.log(rex.test(' '));
\d
表示匹配数字0到9,字符串必须包含一个数字。
let rex = /\d/; console.log(rex.test('dsad5'));
\D
表示匹配一个非数字,字符串中必须包含一个非数字内容。
let rex = /\D/; console.log(rex.test('45645s45612'));
\w
表示匹配数字,字母,下划线,三种字符。
let rex = /\w/; console.log(rex.test('sd45_'));
\W
表示匹配非数字,字母,下划线以外的三种字符。
let rex = /\W/; console.log(rex.test('sd45_'));
.
表示非换行字符,有换行\n以外的字符就返回true。
let rex = /x/; console.log(rex.test('\n'));
\
表示转义符号,将有意义的转无意义的内容,无意义的转有意义的内容。
let rex = /\./; //点原本表示非换行符,通过转义符 变成了匹配一个.。 console.log(rex.test('.'));
边界元字符
用来控制开头结尾内容的元字符。
^
表示匹配字符的开头内容。
let rex = /^xiao/; //返回false 开头需要是xiao而不是xxiao。 console.log(rex.test('xxiaoxie'));
$
表示匹配字符的结尾内容
//表示开头到结尾 为两个数字 let rex = /^\d\d$/; console.log(rex.test('13'));
限定符
写在元字符,或者普通字符后面,用来限定次数的符号。
*
表示需要匹配到0到多个指定字符。
//表示需要匹配到任意个数字字符串。 let rex = /^\d*$/; console.log(rex.test('154544')); true console.log(rex.test('')); true
+
表示需要匹配到1到多个指定字符。
let rex = /^\d+$/; console.log(rex.test('')); false console.log(rex.test('123')); true
?
表示需要匹配到0到一次指定字符。
//字符串中需要有0到1个数字。 let rex = /\d?/; console.log(rex.test('sdfsf')); true console.log(rex.test('sdf123sf')); true
{n}
表示需要匹配到指定次数的指定字符。
//连续五个数字字符串 let rex = /\d{5}/; console.log(rex.test('sddsg458')); false console.log(rex.test('sddsg45458')); true
{n,}
表示需要匹配到n到多次的指定字符。
let rex = /\d{5,}/; console.log(rex.test('12d24545')); true console.log(rex.test('12d245')); false
{n,m}
表示需要匹配到n到m次指定字符串。
let rex = /\d{2,3}/; //是匹配的内容 而不是控制字符串中数字的内容,需要匹配到至少两个数字,只有一个则返回false,有五个数字,则从里面匹配三个数字,返回true。 console.log(rex.test('1ds')); false console.log(rex.test('45465')); true
贪婪和非贪婪
贪婪
当我们使用限定符,捕获字符的时候,它会尽可能的从多捕获,这就是正则的贪婪性。
let rex = /\d{1,5}/ console.log(rex.exec('45684'));
非贪婪
我们只需要在限定符后面再加个?就是非贪婪限定符了,它会优先选择最少的而不是多的。
let rex = /\d{1,5}?/ console.log(rex.exec('45684'));
小练习
练习1
需求
捕获第一个div的完整标签。
代码
<!-- 我们可以通过贪婪限制符号,来获取标签,这是一种常见的场景。 不加?的话,则.会尽可能获取多的内容,左右<>会匹配最外面两边的尖括号。 加上贪婪限制符之后,则会选择最少的内容并 且达成<>的条件。 --> let str = '<div style=" color : "red""></div>' let rex = /<.+?>/ console.log(rex.exec(str));
练习2
let rex = /abcd{2}/; console.log(rex.test('abcddjhgfff')); true <!-- 上面题目中,表示的是两个d 也就是abcdd, 而不是abcabc 如果字符串中包含abcdd则返回true -->
元字符——特殊符号
()
被()括起来的内容,表示一个整体,可以整体括起来进行输出。
<!-- 括起来表示一个整体 所以是匹配两次括号里的内容,也就是需要字符串内包含abcdabcd --> let rex = /(abcd){2}/ console.log(rex.test('dssdabcdabcd')); true
除此之外,还会单独捕获括号内的内容,从左边开始的每一个小括号里的内容都是从索引1开始的数组内容,索引0为匹配到的内容
<!-- 索引0为匹配到的结果abcdefg 索引1为左边开始的第一个小括号 ab 索引2为左边第二个小括号cdefg 索引3为左边第三个小括号de --> let rex = /(ab)(c(de)fg)/ console.log(rex.exec('abcdefghijklmn'));
(?😃
和()的区别就是,这个只有整体效果,不会捕获括号内的数据变成索引内容
let rex = /(?:ab)(?:c(?:de)fg)/ console.log(rex.exec('abcdefghijklmn'));
|
表示或者,会匹配满足的一项内容。
let rex = /123|456/; console.log(rex.exec('212456'));
[]
表示匹配中括号内的任意一项
let rex = /[abcd]/; console.log(rex.exec('graedfsab'));
[^]
表示匹配非中括号内的任意一项
let rex = /[^abcd]/; console.log(rex.exec('graedfsab'));
[n-m]
表示n到m之间的内容,n到m之间的内容实际上是之间的ascll码值。
let rex = /[0-9]/; console.log(rex.exec('g2raedfsab'));
\num
表示前面的某个括号内的东西,重复出现一遍,/1这个数字1不是指的是出现几次,而是指的是第几个小括号内的结果重复来一遍
let rex = /(abc|def)\d+\1/; console.log(rex.test('dsabc123abc')); true console.log(rex.test('dsabc123def')); false
组合形式
[09a-zA-Z_] 等于 \w [^09a-zA-Z_] 等于 \W [0-9] 等于 \d [^0-9] 等于 \D [ ] 等于 \s [^ ] 等于 \S 注意:当.放在[]中只代表一个.,相当于加了转义符
标识符
i
表示忽略大小写
let rex = /[abcdef]/i; console.log(rex.test('ABC')); true
g
表示全局查找,或许应该叫动态查找,跟动态变量一样,下次的查找会遵循上一次查找的位置继续查找,如果查找不到了就返回null,还继续查找的话,会从头开始。对于字符串match方法加了g,则会一次性返回所有匹配内容
let rex = /\d{1}/g console.log(rex.exec('123')); console.log(rex.exec('123')); console.log(rex.exec('123')); console.log(rex.exec('123')); console.log(rex.exec('123')); console.log(rex.exec('123')); let rex = /es(?=2015|2016)/g let str = 'es2015es2016es2017' console.log(str.match(rex));
y
粘性全局跟g的区别就是粘性全局不能间隔捕获,也就是第一个匹配的内容必须从【0】开始就捕获到,第二个内容必须从第一个内容的结束位开始就捕获到,如果没有捕获到就返回null,下次捕获就从头开始。
let rex = /\d{1}/y console.log(rex.exec('123')); console.log(rex.exec('1g2g3')); console.log(rex.exec('123')); console.log(rex.exec('12g3')); console.log(rex.exec('123'));
小练习
练习1
let rex = /^(abc|def){2}$/; console.log(rex.test('abcabc')); true console.log(rex.test('defdef')); true console.log(rex.test('abcdef')); true console.log(rex.test('defabc')); true
练习2
验证一个字母字符串,只能由数字字母下划线组成,6到12位,不能以_开头。
let rex = /^[a-zA-Z0-9]\w{5,11}$/; console.log(rex.test('ads54s_')); console.log(rex.test('_ads54s')); console.log(rex.test('%ads54s'));
练习3
正则验证数字,验证0-255
思路:把0-255数字分成几类
一位数 \d
两位数 \d{2}
1开头的三位数 1\d{2}
2开头的第二位是0-4的三位数 2[0-4]\d
2开头的第二位是5的第三位为0-4的三位数 2[5]\d
let rex = /^(\d|\d{2}|1\d{2}|2[0-4]\d|25[0-5])$/ 修改后 let rex = /^(1?\d{1,2}|2[0-4]\d|25[0-5])$/ console.log(rex.test('0454441')); false console.log(rex.test('234')); true console.log(rex.test('123')); true console.log(rex.test('25622')); false
练习4
邮箱匹配
邮箱@前的字符为6到10位,不能以下划线开头,只能由数字字母下划线组成,只能是qq 网易163邮箱,后缀只能是.com或.cn
let rex = /^[0-9a-zA-Z]\w{5,9}@(qq|163)(.com|.cn)$/; console.log(rex.test('22175451@163.com')); true
正则的预查
正向预查
正向肯定
(?=)
捕获某个内容的时候,可以增添条件,比如后面需要连接什么,例如,我想吃泡面,吃老坛酸菜的,泡面是内容,老坛酸菜是条件
<!-- 匹配es2015或者es2016,这种符合要求的, 匹配到了之后,得到es。也就是说 我要拿到es,但是我要拿到es2015或者2016里面的es --> let rex = /es(?=2015|2016)/; console.log(rex.exec('es2015')); console.log(rex.exec('es2016')); console.log(rex.exec('es2017'));
正向否定
(?!)
捕获某个内容的时候,可以增添条件,比如后面不需要连接什么,例如,我想吃泡面,不吃老坛酸菜的,泡面是内容,不吃老坛酸菜是条件
let rex = /es(?!2015|2016)/; console.log(rex.exec('es2015')); console.log(rex.exec('es2016')); console.log(rex.exec('es2017'));
负向预查
负向肯定
跟正向肯定一样,区别就是,负向的肯定的条件在前面。
(?<=)
let rex = /(?<!2015|2016)es/; console.log(rex.exec('2015es')); console.log(rex.exec('2016es')); console.log(rex.exec('2017es'));
let rex = /(?<=2015|2016)es/; console.log(rex.exec('2015es')); console.log(rex.exec('2016es')); console.log(rex.exec('2017es'));
负向否定
跟正向否定一样,区别就是,负向的否定的条件在前面。
let rex = /(?<!2015|2016)es/; console.log(rex.exec('2015es')); console.log(rex.exec('2016es')); console.log(rex.exec('2017es'));
字符串与正则合作的几个方法
search()
这个方法就是查找匹配对象的索引位置,只返回索引位置。
let rex = /a/ let str = 'dsa'; console.log(str.search(rex)); 2
replace()
使用正则表达式替换字符串,没有\g的时候只会替换第一个匹配的,有\g则替换掉所有匹配符合的内容。
let str = '11111' console.log(str.replace(/1/g, 'a')); console.log(str.replace(/1/g, function (data) { return Number(data) + 1; }));
match()
跟exec类似,区别就是正则表达式为g的时候会匹配所有符合的内容
let rex = /es(?=2015|2016)/g let str = 'es2015es2016es2017' console.log(str.match(rex));
search()
这个方法就是查找匹配对象的索引位置,只返回索引位置。
let rex = /a/ let str = 'dsa'; console.log(str.search(rex)); 2
replace()
使用正则表达式替换字符串,没有\g的时候只会替换第一个匹配的,有\g则替换掉所有匹配符合的内容。
let str = '11111' console.log(str.replace(/1/g, 'a')); console.log(str.replace(/1/g, function (data) { return Number(data) + 1; }));
match()
跟exec类似,区别就是正则表达式为g的时候会匹配所有符合的内容
let rex = /es(?=2015|2016)/g let str = 'es2015es2016es2017' console.log(str.match(rex));