你可能不知道的正则表达式用法

正则表达式基础

字面量匹配

直接书写正则表达式

特殊字符

  1. . 表示匹配任意字符
  2. ^ 表示字符串的开始
  3. $ 表示字符串的结束

转义符

  1. \n 匹配换行符
  2. \r 匹配回车符
  3. \t 匹配制表符,即缩进
  4. \s 匹配任何空白字符, 包含空格、回车、换行、制表等
  5. \S 匹配任何非空白字符
  6. \b 匹配单词边界,有空白才有边界
  7. \B 匹配非单词边界
  8. \d 匹配数字
  9. \D 匹配非数字
  10. \w 匹配字母、数字、下划线,等价于’[A-Za-z0-9_]’
  11. \W 匹配非字母、数字、下划线。等价于 ‘[^A-Za-z0-9_]’
  12. \u 匹配unicode编码

转义字符

\ 转义字符可以将特殊字符转化为普通字符

字符集

[]: 匹配一个字符, [] 内写范围

[^]:取反,匹配该范围之外的
 匹配中文:[\u4e00-\u9fa5]

量词

    • 零个或多个
    • 一个或多个
  1. ?零个或一个
  2. {n} 匹配n个
  3. {n,} 匹配>=n个
  4. {n,m} 匹配n到m个

或者

| 表示多个规则之间任选其一

子表达式

() 单独的一个规则

标识位

  • i 忽略大小写
  • g 全局匹配
  • m 匹配多行
    var reg = /\d+/gim;
练习
  • 匹配手机号
    ^1\d{10}$
  • 姓名3-6位
    ^[\u4e00-\u9fa5]{2,6}$
  • 密码6-12位,数字、字母下划线
^\w{6,12}$
^\w+@\w+(\.\w+){1,2}$
  • 座机号:xxxx-xxxx
^\d{4}-\d{7}$
  • 正数(正小数、正整数)
^\d+(\.\d+)?$
  • 小数(正负小数)
 ^[\d|-\d]+(\.\d+){1}$
  • 整数(正负整数)
^[\d|-\d]+$

RegExp

创建正则表达式的方式

  • 字面量
var reg = /\w+/gi;
  • 构造函数
var reg = new RegExp(/\w+/,"gi");
var reg = RegExp(/\w+/, "gim");

正则实例

对象.属性(实例属性),实例属性是属于某个实例对象的私有的属性

类.属性(静态属性),静态属性是所有对公有的属性

静态属性

  • RegExp.prototype.global:判断是否开启全局匹配,返回boolean,只读
  • RegExp.prototype.ignoreCase:是否开启忽略大小写,返回boolean,只读
  • RegExp.prototype.multiline:是否开启多行匹配,返回boolean,只读
  • RegExp.prototype.source:返回该正则表达式
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNYjse8S-1574150938035)(EF9C08E538F6498DAC43360870E43038)]

静态方法

  • RegExp.prototype.test测试某个字符串是否满足规则, 如果匹配到字符串返回true, 反之为false
var reg = /^(\d|-\d)+$/g;
console.log(reg.test('120'));
注意点:当是全局匹配时,test()函数会从上一次匹配的结束处重新开始匹配
// lastIndex是RegExp的静态属性, 表示匹配的开始位置
var reg = /abc/g;
console.log(reg.lastIndex, reg.test('124abc123abc123'))
console.log(reg.lastIndex, reg.test('124abc123abc123'))
console.log(reg.lastIndex, reg.test('124abc123abc123'))
console.log(reg.lastIndex, reg.test('124abc123abc123'))
console.log(reg.lastIndex, reg.test('124abc123abc123'))
console.log(reg.lastIndex, reg.test('124abc123abc123'))
打印结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8xonxxMs-1574150938036)(8B7BF58D72D24E6EB1CEB066A35DFFDE)]

可以看出使用test()函数匹配是循环的,每匹配一次,第二次从上一次匹配结束的下一位进行匹配,直到匹配结束,再从头开始

利用这个特点test函数这个特点,我们可以得到目标字符串内有多少个符合正则表达式的字串,请看下面代码:
var reg = /abc/g;
var i = 0;
while(reg.test('124abc123abc123')){
    i++;
}
console.log(i); // 2

贪婪模式

正则表达式默认情况,使用贪婪模式,即尽可能多的匹配

如果想不使用贪婪模式,需要在量词后添加?

var reg = /\d+?/g; // 尽可能匹配少的数字

  • RegExp.prototype.exec():execute, 执行匹配,返回匹配结果,如果匹配不到返回null
    exec()函数的返回值包含:匹配到的目标字符串,匹配的起始地位,如下:
 var s = '123abc123abc123abc';
 var reg = /\d+/g;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3kHcBdV-1574150938036)(2AA181092069445FA1FEAE5D278F26C3)]

字符串中与正则相关的方法

String.prototype.match(reg):返回匹配结果
全局匹配时,返回匹配到的结果数组
var str = '121aba124aba1213aba';
var reg = /\d+/g;
console.log(str.match(reg))// ["121", "124", "1213"]
非全局匹配返回值与exec()相同
String.prototype.search(reg):返回第一次匹配的下标
String.prototype.split(reg, num):按照正则表达式内的字符分割,返回分割结果数组;num表示取分割结果的前几位
var str = '1234 djksfj sdklfj   sdkfj'
var reg = /[ f]+/g;  //按照制空格和字母f进行分割
console.log(str.split(reg)); // ["1234", "djks", "j", "sdkl", "j", "sdk", "j"]
String.prototype.replace(reg, func/str): 替换

replace第一个参数写正则表达式,第二参数可以为字符串也可以为函数

第二个参数为函数时:函数的第一个参数匹配到的字符串

例:将"hello word"转换为小驼峰命名
var str = '\tjavascript\nvue react es6 webpack css3 html5'
var newStr = str.replace(/\s*\b[a-z]/g, function (match) {
    if(str.match(/\s*\b[a-z]/)[0] === match) return match.trim();
    return match.toUpperCase().trim();
})
console.log(newStr) // javascriptVueReactEs6WebpackCss3Html5
练习
  1. 匹配任意一个字符串,得到匹配到的次数和匹配到的结果
  2. 得到一个字符串中中文字符的数量
  3. 过滤一敏感词,有一个敏感词数组,将给定字符串中的敏感词替换为****
  4. 得到一个html字符串中出现章节的数量
var str = '123213';
var reg = new RegExp(/\d/g,'g');
var i = 0;
var res;
while(res = reg.exec(str)){
    i++;
    console.log(res[0])
}
console.log(`共匹配${i}次`)
var str = '1大解放路口空间的萨拉克服2十大科技风凉开水3213';
var reg = new RegExp(/[\u4e00-\u9fa5]/g,'g');
var i = 0;
while(reg.test(str)){
    i++;
}
console.log(`共有${i}个中文字符`)
// 实现方式1
var str = '1大解放路口空间的萨拉克营销服jiao yi2十大科共产党技风毒凉du开水3213';
var arr  = ['共产党', '营销', 'du', '毒','jiao yi'];
for(var i = 0; i < arr.length ; i++){
    str = str.replace(new RegExp(arr[i],'g'), '****');
}
console.log(str)

// 实现方式2
var str = '1大解放路口空间的萨拉克营销服jiao yi2十大科共产党技风毒凉du开水3213';
var arr  = ['共产党', '营销', 'du', '毒','jiao yi'];
str = str.replace(RegExp(`(${arr.join('|')})+`, 'g'), '****');
console.log(str)
var html =`

第1章

第2章

第3章

第4章

第5章

第100章

第7章

` var reg = /第\d+章/g; var i = 0; while(reg.test(html)) i++; console.log(`共${i}个章节`)

正则表达式高级用法

捕获组

小括号包裹的部分叫捕获组,捕获组会出现在匹配结果中

RegExp.prototype.exec()中的捕获组

示例代码

var str = '123abc-789ab-456abc';
var reg = /(\d)+\w+/g;
var res;
while(res = reg.exec(str)){
    console.log(res)
}

执行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ht2XPT53-1574150938037)(F4C34C5C431A4BF187140A3BCB361F32)]
每个被红色方框圈起来的部分就是每一个捕获组的捕获值,也就是我们正则表达式中(\d)匹配到的值。也就是说在一次匹配中捕获组捕获到的值,会从索引1向后依次排列

那么捕获组有什么用呢?看下面的例子

现在有一个需求,给定一个字符串为’2000-10-10,2019-10-14,2019-11-18’, 让我们输出每一个日期,并且输出每一个年月日

var str = '2000-10-10,===2019-10-14/2019-11-18';
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g;
while(res = reg.exec(str)){
    console.log(`${res[0]} ${res[1]} ${res[2]} ${res[3]}`)
}
// 2000-10-10 2000 10 10
// 2019-10-14 2019 10 14
// 2019-11-18 2019 11 18

打印exec函数匹配结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xiYGIhXe-1574150938038)(29981DFBF9B2496696013DA3B2BD80E1)]
可以看出我们不仅能得到每次匹配的字符串,还可以得到具体匹配的字符串的字串,这就是捕获组的真正作用

具名捕获组

我们还可以给每个捕获组命名

命名方式:在每个()内部的最前面写?,如

// 分别给每个捕获组命名为 year month day
var reg = /(?\d{4})-(?\d{1,2})-(?\d{1,2})/g;

可以通过exec()函数的返回值group对象获取,让我们利用这个特性修改上述代码,可以得到相同的代码

var str = '2000-10-10,===2019-10-14/2019-11-18';
var reg = /(?\d{4})-(?\d{1,2})-(?\d{1,2})/g;
while(res = reg.exec(str)){
    console.log(`${res[0]} ${res.groups.year} ${res.groups.year} ${res.groups.year}`)
}

让我们再次打印exec函数匹配结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WcXHAl5t-1574150938039)(A79046E894684CD294AD9DFA07F6EA85)]
可以发现groups内有出现了我们的捕获组,我们发现,原来groups保存的是具名捕获组的值

非捕获组

捕获组的执行是浪费效率的,但捕获又是默认,如果不是特殊需要我们只是想把()内的正则表达式作为一个整体,不想使用捕获功能,那么就需要用到非捕获组

触发方式:在每个()内部的最前面写?:,如

var reg = /(?:\d{4})-(?:\d{1,2})-(?:\d{1,2})/g;

这样我们就不会再exec执行结果看见捕获组了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2HCNf6S-1574150938039)(2F661DF8FE514AC2AA62356D464CA906)]

String.prototype.replace()中的捕获组
  • 函数形式-replace第二个参数
var str = '2000-10-10-4,===2019-10-14-5/2019-11-6-18~2019-11-18';
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})-(\d{1,2})/g;
str.replace(reg, function (match, g1, g2, g3, g4,index, self) {
    console.log(...arguments)
})
// 这里正则表达式中有四个捕获组
// 函数从第1个到第1+4个参数就为捕获组捕获到的值 
// 剩下两个参数为匹配的起始位置和输入的字符串
  • 字符串形式-replace第二个参数

捕获组用$1、$2、$3表示,如

var str = '2000-10-10-4,===2019-10-14-5/2019-11-6-18~2019-11-18';
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})-(\d{1,2})/g;
str.replace(reg, '年$1月$2日$3小时$4')

反向引用

正则表达式中使用某个数组,使用方式:\捕获组编号\k

查找出’aaaaabbbbbddddddddddcccccdewdddkkkk’中出现的连续字符

// 非具名捕获组
var str = 'aaaaabbbbbddddddddddcccccdewkkkk';
var reg = /(\w)\1+/g;
while(res = reg.exec(str)){
    console.log(res[1])
}

// 具名捕获组
var str = 'aaaaabbbbbddddddddddcccccdewkkkk';
var reg = /(?\w)\1+/g;
while(res = reg.exec(str)){
    console.log(res.groups.char)
}

正向断言-预查

检查某个字符串是否满足某个规则,该规则不成为匹配结果也不成为捕获组

这个规则的就叫正向断言,使用方式为(?=)

面试题

用正则表达式将’1123123123123’转换为’1,123,123,123,123’

var str = '123123123123'

var reg = /\B(?=(\d{3})+$)/g; // 断言内的所有()都不会成为匹配结果与捕获组

console.log(str.replace(reg, ','));

反向断言-预查

检查某个字符串是否满足某个规则,该规则不成为匹配结果也不成为捕获组

这个规则的就叫反向断言,使用方式为(?!)

实际应用题

密码强度判断

function jugdePWD(pwd){
    if(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*.]).{6,12}$/.test(pwd)){
        return '强'
    }else if(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{6,12}$/.test(pwd)){
        return '中'
    }else if (/^(?=.*[a-z])(?=.*[A-Z]).{6,12}$/.test(pwd)){
        return '弱'
    }else {
        return '不满足条件'
    }
}
console.log(jugdePWD('AAAAAi1$'));

你可能感兴趣的:(正则表达式,正则表达式)