正则表达式 – 渡一袁老师

基础

  1. 字面量匹配

    规则中直接书写字面量字符

  2. 特殊字符
    .  // 匹配任意一个字符
    ^  // 匹配字符串开始
    $  // 匹配字符串结束
    
    例如:
    规则:a123...$
    a1234     false
    a123456   true
    b12345677 false
  3. 转义符:\
    \n      // 换行符
    \r		// 回车符
    \t		// 制表符(Tab键)
    \s		// 任意空白字符
    \S		// 除了任意空白字符以外字符(\s取反)
    \b		// 单词边界
    \B		// 非单词边界
    \d		// 匹配一个0-9的数字
    \D		// 非 数字
    \w		// 数字、字母、下划线
    \W		// 非 数字、字母、下划线
    \un		// 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符
    
  4. 字符集:[]
    [字符范围]	// 匹配中括号里任意一个字符
    [^字符范围] // 注意:^符号如果加在字符串规则最前面表示以X开始,如果放字符集里最前面表示对字符范围取反,例如:[^0-9]匹配非数字相当于\D
    
    匹配中文:[\u4e00-\u9FA5]
    
  5. 量词:前面的规则出现的次数
  6. 或者:多个规则之间,适用或者 |,表示多个规则任选其一

JS中的应用

js中,正则表达式表现为一个对象,该对象是通过构造函数RegExp

创建正则对象

  1. 字面量模式

  2. 构造函数模式

// reg1等价于reg2
var reg1 = /^-?\d+(\.0+)?$/;
var reg2 = new RegExp("^-?\d+(\.0+)?$");

// 替换敏感词
var senWords = ["抽烟","喝酒","烫头"];

function removeSensitiveWords (s,rep) {
    // 此处用需要用构造函数模式 /抽烟|喝酒|烫头/g
    var reg = new RegExp(senWords.join("|"),"g");
    return s.replace(reg,rep);
}
console.log(removeSensitiveWords("skjf抽地烟daf喝酒95995烫头发66","***")); // skjf抽地烟daf***95995***发66

正则实例成员

  • global:全局匹配
  • ignoreCase:忽略大小写
  • multiline:多行匹配
  • exec方法:execute,执行匹配,得到匹配结果
  • test方法:验证某个字符串是否满足规则
    // 匹配一个字符串中 中文出现的次数 
    var str = "fsf的接口拉菲接sdsd多少sd问问sdddsd发"; 
    var reg = /[\u4e00-\u9fa5]/g; var n = 0;
    while (reg.test(s)) {
        n++; 
    } 
    console.log(n);  // 11
    
    贪婪模式

    正则表达式,默认情况下,适用贪婪模式(尽可能多匹配)

    在量词后,加上?,表示进入非贪婪模式

字符串中正则方法

  • split:以某种规则分割字符串
    // 把一个字符串按照非数字、字母、下划线规则分割
    var str = "abc def\tgg,ffh&&j";
    str.split(/\W/) //  ['abc', 'def', 'gg', 'ffh', '', 'j']
    
  • search:得到匹配下标
    var str = 'abgdkljkf'
    str.search(/d/g) // 3
    
  • match:得到匹配结果
    var str = "1234abc123aaa";
    var result = str.match(/\d+/g);
    console.log(result); // ['1234', '123']
    
  • replace:替换
    // 替换字符串中首字母为大写
    var str = 'hello world';
    str = str.replace(/\b[a-z]/g, function(match) {
        return match.toUpperCase();
    })
    console.log(str) // Hello World
    
    // 替换首字母为大写,并且去掉空格换行制表符都特殊字符
    var str = 'hello world\tjavascript\nyes';
    str = str.replace(/\s*\b[a-z]\s*/g,function(match){
        return match.toUpperCase().trim();
    })
    console.log(str) // HelloWorldJavascriptYes
    

进阶

捕获组

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

语法:()

// 得到每一个日期,并且得到每个日期的年月日
var s = "2015-5-1, 2016-6-18, 2000-08-28";
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g;
while (result = reg.exec(s)) {
    var r = `${result[0]}, ${result[1]}, ${result[2]}, ${result[3]}`;
	console.log(r);
    // 2015-5-1, 2015, 5, 1
	// 2016-6-18, 2016, 6, 18
	// 2000-08-28, 2000, 08, 28
}

捕获组占位符:两种形式

var s = "2015-5-1, 2016-6-18, 2000-08-28";
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g;

// 1.
// 占位符:$1表示第一个捕获组,$2表示第二个捕获组
// s = s.replace(reg,"$1/$2/$3"); // 2015/5/1...

/**
* 2.
* reg:		正则表达式规则
* match: 	匹配的结果
* g1/g2/g3:捕获组
*/
s.replace(reg,function(match,g1,g2,g3){
    console.log(match,g1,g2,g3);
    // 2015-5-1, 2015, 5, 1
	// 2016-6-18, 2016, 6, 18
	// 2000-08-28, 2000, 08, 28
})

具名捕获组:捕获组可以命名,叫做具名捕获组:小括号()最前方加上?<name>

var s = "2015-5-1, 2016-6-18, 2000-08-28";
var reg = /(?<year>\d{4})-(?<month>\d{1,2})-(?<day>\d{1,2})/g;
while (result = reg.exec(s)) {
	console.log(result.groups,result.groups.year,result.groups.month,result.groups.day);
	// {year: '2015', month: '5', day: '1'} '2015' '5' '1'
	// {year: '2016', month: '6', day: '18'} '2016' '6' '18'
	// {year: '2000', month: '08', day: '28'} '2000' '08' '28'
}

非捕获组:小括号()最前方加上?:

反向引用

反向引用:引用之前的捕获组

语法:\n

// 【\1】: 捕获组后面加上“\1”,引用前面的捕获组重复一次
var reg = /(\d{2})\1/g;
var s = "1313";
console.log(reg.test(s)); // true
var s2 = "1334";
console.log(reg.test(s)); // false 捕获到的是13 重复后是1313
// 例1:找出该字符串中连续的字符(abcg)
// var s = "aaaaaabbbbbbcccccccdefgggggg"
var s = "aaaaaabbbbbbcccccccdefgggggg";
var reg = /(\w)\1+/g;
while (result = reg.exec(s)){
    console.log(result[1]); // a b c g
}

正向断言(预查)

正向断言:检查某个字符后面的字符是否满足某个规则,该规则不成为匹配结果,并且不成为捕获组

语法:?=

// 找出后面是数字的字母(不要后面数字,但是要检查后面有没有数字) :f a d
var s = "sdsdsf345dsa45dafd5533434trt";
var reg = /[a-z-A-Z](?=\d+)/g; // 此处()里面不是捕获组 而是检测前面的字母后面是否有数字(\d+) 
while (result = reg.exec(s)) {
    console.log(result); // f a d
}
// 面试题:把一个数字从右到左,每隔三位加上一个,
var s = '893889659';

//  3个数字出现一次或多次(整个是一个正向预查)
var reg = /\B(?=(\d{3})+$)/g;  // 如果不加\B  则刚好是3的倍数时 第一位会出现,
s = s.replace(reg, ",");
console.log(s); // 893,889,659

负向断言(预查)

正向断言:检查某个字符后面的字符是否不满足某个规则,该规则不成为匹配结果,并且不成为捕获组

语法:?!

// 找出后面没有数字的字母:a f r s
var s = "afg5d6rsp9";
var reg = /[a-zA-Z](?!\d+)/g;
while (result = reg.exec(s)) {
    console.log(result); // a f r s
}
// 面试题:判断密码强度(要求密码中必须出现小写字母、大写字母、数字、特殊字符(!@#_,.))

// ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#_,.]): 这一部分是检查是否存在大/小写字母,数字,特殊字符
// 如果满足要求再去匹配6-12位
var reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#_,.]).{6,12}$/;
console.log(reg.test("24dff34A.")); // true
console.log(reg.test("24dff34A")); // false
console.log(reg.test("24dff34A.888888888")); // false
/** 
* 判断密码强度综合版
* 密码长度必须是6-12位
* 出现小写字母、大写字母、数字、特殊字符(!@#_,.)  -> 强
* 出现小写字母、大写字母、数字  -> 中
* 出现小写字母、大写字母  -> 弱
* 其他 -> 不满足要求
*/

function judgePwd(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(judgePwd("ABGcdf58."));	// 强
console.log(judgePwd("ABGcdf88"));	// 中
console.log(judgePwd("ABGcdf"));	// 弱
console.log(judgePwd("ABGcd"));		// 不满足要求