sd
基础
var str = 'aabc ac abbc sadgc abbbc abbbbbc dsf a1c a5c a3c a2xc a-c'
var reg = /ab{2,5}c/g
// var res = str.match(reg);
// console.log(res); [ 'abbc', 'abbbc', 'abbbbbc' ]
var reg1 = /a[b123]c/g
// var res1 = str.match(reg1);
// console.log(res1); [ 'abc', 'a1c' ]
var reg2 = /a[1-3a-z]c/g
// var res2 = str.match(reg2);
// console.log(res2); [ 'abc', 'a1c', 'a3c' ]
// 匹配 1 - 3
// var reg3 = /a[-31]c/g
// var reg3 = /a[-13]c/g
var reg3 = /a[1\-3]c/g
// var res3 = str.match(reg3);
// console.log(res3); [ 'a1c', 'a3c', 'a-c' ]
var reg4 = /\s+/g
var res4 = str.match(reg4);
// console.log(res4);
var reg5 = /a[\S]*c/g
// var res5 = str.match(reg5);
// console.log(res5);
var reg6 = /ab?c/g
var res6 = str.match(reg6);
// console.log(res6); [ 'abc', 'ac' ]
// 惰性匹配
var reg7 = /[a-z]{2,5}?/g
// var res7 = str.match(reg7);
// console.log(res7);
// 多选分支
var reg8 = /a\Sc|s\S+c/g
// var res8 = str.match(reg8);
// console.log(res8);
// 匹配颜色 ???
var str2 = "#ffbbad #Fc01DF #FFF #ffE a#333";
var reg9 = /#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})/g
// var res9 = str2.match(reg9);
// console.log(res9);
// 匹配时间 ????
var timeList = '23:59 26:12 -6:12 12:60 20:12 07:65 06:15 21:45 a06:16';
var reg10 = /([01]\d|[2][0-3]):[0-5]\d/g
// var res10 = timeList.match(reg10);
// console.log(res10);
// 匹配时间 07:09可以写成 7:9
var timeList2 ='23:59 06:7 21:05 5:05 6:1 26:12 -6:12 12:60 07:65';
var reg11 = /(0?\d|1\d|2[0-3]):(0?\d|[1-5]\d)/g;
var reg12 = /(0?[0-9]|1[0-9]|[2][0-3]):(0?[0-9]|[1-5][0-9])/g;
// var res11 = timeList2.match(reg12);
// console.log(res11);
// console.log(reg11.test('7:9'));
// 匹配日期 YYYY-dd-mm
var time1 = '0220-11-01 2012-13-01 2021-01-1 2021-12-01'
var reg13 = /\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])/g;
// var res13 = time1.match(reg13);
// console.log(res13);
// 匹配 路径
// E:\bk
// D:\Officecode\sourceCode1\public\static\bimUI\3dcloud\说明文档.docx
// /^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/
var reg13 = /^[a-zA-Z]:\([^\:*"?|<>\n\r/]+\)*([^\:*"?|<>\n\r/]+)?$/;
// console.log(reg13.test("E:\bk"));
// 匹配id 量词*可以匹配多个 使用惰性匹配第一次遇到 引号就停止
var str5 = '<div id="container" class="main"></div>';
// var reg15 =/id=".*?"/; // 回溯
var reg15 =/id="[^"]*"/;
console.log(str5.match(reg15)[0]);
位置匹配
// 开头结尾 ^ $
let res1 = 'hello'.replace(/^|$/g,'#'); // #hello#
// 多行匹配模式 修饰符 m表示多行
let res2 = "I\nlove\njavascript".replace(/^|$/gm,'#');
// #I#
// #love#
// #javascript#
// \b 是单词边界,具体就是 \w 与 \W 之间的位置,也包括 \w 与 ^ 之间的位置,和 \w 与 $ 之间的位置
// \w表示 [a-zA-Z0-9_]
let res3 = "[JS] Lesson_01.mp4".replace(/\b/g,'#'); //[#JS#] #Lesson_01#.#mp4#
// \B 非单词边界 在字符串中所有位置中,扣掉 \b,剩下的都是 \B 的。
// 具体说来就是 \w 与 \w、 \W 与 \W、^ 与 \W,\W 与 $ 之间的位置。
let res4 = "[JS] Lesson_01.mp4".replace(/\B/g,'#'); //#[J#S]# L#e#s#s#o#n#_#0#1.m#p#4
// (?=p) 表示p前面的位置,或者该位置后面要匹配p 正向先行断言
let res5 = 'hello'.replace(/(?=l)/g,'#'); //he#l#lo
// (?!p) 与 (?=p) 相反 负向先行断言
let res6 = 'hello'.replace(/(?<!l)/g,'#'); //#h#ell#o#
// (?<=p) 表示后面的位置
let res7 ='hello'.replace(/(?<=l)/g,'#'); //hel#l#o
// (?<!p) 与 (?<=p)相反
let res8 ='hello'.replace(/(?<!l)/g,'#'); // #h#e#llo#
// console.log(res8);
// 位置的特性
// 对于位置的理解,我们可以理解成空字符 ""
// 'hello' = ''+'h'+''+'e'+''+'l'+''+'l'+''+'o' = ''+''+'hello'+''
// console.log(/^hello$/.test('hello')); //true
// console.log(/^^^^^hello$$$$$$$$/.test('hello')); // true 这里多个 ^ 和 $表示可以匹配多个空 ''
// console.log(/(?=he)^^he(?=\w)llo$\b\b$/.test('hello'));
// 数字的千位分割
let str1 = '111234567890';
// \d{3}表示三位数字一组 至少出现一次 +
let res9 = str1.replace(/(?=(\d{3})+$)/g,','); //,111,234,567,890
// 非开头加上逗号
let res10 = str1.replace(/(?!^)(?=(\d{3})+$)/g,','); //111,234,567,890
// 如果要把 "12345678 123456789" 替换成 "12,345,678 123,456,789"
let str2 = "12345678 123456789";
let res11 = str2.replace(/(?!\b)(?=(\d{3})+\b)/g,','); // 12,345,678 123,456,789
// (?!\b)非边界字符 等价于 \B
let res12 = str2.replace(/\B(?=(\d{3})+\b)/g,','); // 12,345,678 123,456,789
// 货币表示法 1888 转化为 $ 1,888.00
let str3='1888';
let res13 = parseFloat(str3).toFixed(2).replace(/\B(?=(\d{3})+\b)/g,',').replace(/^/,'$ ');
// 密码 数字 大小写 6 到12 位,必须至少包含两种字符
// (?=.*\d)类比 (?=p)表示p前面的位置,或者说该位置后面要跟上p
// 同理表示该位置后面要有 任意多个字符 且有数字,即需要包含数字
// let res14 = /(?=.*\d)/g
// console.log(res14.test('sd .gfh sd0f'));
// 第一种 需要包含 数字和大写 数字和小写 小写和大写 6到12位
let reg1= /((?=.*\d)(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])|(?=.*[a-z])(?=.*[A-Z]))^[\da-zA-Z]{6,12}$/
// 第二种 可选大小写数字 但是不能全是其中一种
let reg2 = /(?!^\d{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[\da-zA-Z]{6,12}$/
// 将字符串想想为多个空白符凭借而成,当前位置可以是空白符后面匹配用 (?=)或者是(?!)
括号的作用
let reg1= /\d{4}-\d{2}-\d{2}/
// console.log('2021-12-01'.match(reg1));
// [ '2021-12-01', index: 0, input: '2021-12-01', groups: undefined ]
let reg2 = /(\d{4})-(\d{2})-(\d{2})/
// let res1 = '2021-12-01'.match(reg2);
// reg2.test('2021-12-01')
// console.log(RegExp.$1); //2021 $1对应第一个分组
// console.log(RegExp.$2); //12 $2对应第二个分组
// console.log(RegExp.$3); //01 $3对应第三个分组
// 将 yyyy-mm-dd 转换为 mm/dd/yyyy 05/12/2012
// console.log('2012-05-12'.replace(/(\d{4})-(\d{2})-(\d{2})/,'$2/$3/$1'));
// 反向引用
// 需要匹配 yyyy-mm-dd yyyy/mm/dd yyyy.mm.dd 但不匹配 yyyy-mm/dd
// \1 表示第一个分组 $1 (-|\/|\.) ; \2 \3 表示第二第三个分组
reg3 = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
// 多括号 以左括号(开括号)为准
reg4 = /^((\d)(\d(\d)))\1\2\3$/
// reg4.test('123123123')
// console.log(RegExp.$1); //123 表示最外层括号(第二个开括号)的分组 ((\d)(\d(\d)))
// console.log(RegExp.$2); // 1 第二个开括号 表示 (\d)
// console.log(RegExp.$3); // 23 第三个开括号 (\d(\d))
// console.log(RegExp.$4); // 3 第四个开括号 (\d)
// 分组后的量词 分组最终捕获到的数据是最后一次的匹配
reg5=/(\d)+ \1/
// console.log(reg5.test('123456 1')); // false
// console.log(reg5.test('123456 6')); // true 分组最后一次匹配6,所以\1 表示6
// 非捕获括号 如果只想要括号最原始的功能,但不会引用它;不使用$1 \1 这种
reg6=/(ab)+/g
// console.log('ababa abba abababb'.match(reg6)); //[ 'abab', 'ab', 'ababab' ]
reg7 =/(?:ab)+/g
// console.log('ababa abba abababb'.match(reg7)); //[ 'abab', 'ab', 'ababab' ]
// 模拟字符串的trim功能
// console.log(' food '.replace(/^\s+|\s+$/g,'')); //food
reg8 = /^\s*(.*?)\s*$/g;
// (.*?)表示 惰性匹配所有字符 从开头 非空\s后到 一遇到 结尾的第一个空\s前 就结束
// reg8.test('... ddfs .. ');
// console.log(RegExp.$1); //... ddfs ..
// console.log(' food '.replace(reg8,'$1')); //food
// 将每个单词首字母转化为大写
reg9 = /(^|\s)\w/g;
newStr = 'my name is epeli'.replace(reg9,function(a,b,c,d){
return a.toUpperCase(); //a表示匹配到的
})
// console.log(newStr); // My Name Is Epeli
// (^|\s) 表示 空或者开头 下一个\w 就是需要变成大写的
// 驼峰化 (.)? 妙用 结尾是 空格的时候只到空格的下一位可以是 空格或者空
reg10=/[-_\s](.)?/g;
newStr2 = '-moz-transform '.replace(reg10,function(a,b){
// console.log(a); // -m -t 匹配到所有的
// console.log(b); // m t 第一个分组
b=b?b:'';
return b.toUpperCase()
})
// console.log(newStr2); //MozTransform
// 中划线化 驼峰化的逆过程
// console.log(' MozTransform '.replace(/^\s*(.*?)\s*$/g,'$1').replace(/([A-Z])/g,'-$1').replace(/[-_\s]+/g,'-').toLowerCase());
// html的转义和反转义
var escapeChars = {
'<' : 'lt',
'>' : 'gt',
'"' : 'quot',
'&' : 'amp',
'\'' : '#39'
};
let resN = '<div>Blah blah blah</div>'.replace(new RegExp('['+Object.keys(escapeChars).join('')+']','g'),function(a){
return '&' + escapeChars[a]+';';
})
// console.log(resN); // <div>Blah blah blah</div>
// 反转义
var htmlEntities = {
nbsp: ' ',
lt: '<',
gt: '>',
quot: '"',
amp: '&',
apos: '\''
};
let resNs = '<div>Blah blah blah</div>'.replace(/\&([^;]+);/g,function(a,b){
if (b in htmlEntities) {
return htmlEntities[b];
}
return a;
});
// console.log(resNs);
// 匹配成对 标签
let reg11 = /<([^>]+)>[\d\D]*<\/\1>/g
console.log(reg11.test('<p>this </p>'));
console.log(reg11.test('<p>this </strong>'));
回溯法原理
正因为有多种可能,所以要一个一个试。直到,要么到某一步时,整体匹配成功了;要么最后都试完后,发现整体匹配不成功
// 量词回溯
reg1= /ab{1,3}?c/g
// 发生了回溯,匹配第一次 a ; 第二次 ab ; 第三次 abb ;第四次 abbb; 出错了 ;回退到第三次,匹配abbc 完成
// console.log('abbc'.match(reg1));
// 惰性匹配回溯
var string = "12345";
//没有出现回溯,先匹配1 后面匹配234, 没有发生 回退
var regex = /(\d{1,3}?)(\d{1,3})/; // [ '1234', '1', '234', index: 0, input: '12345', groups: undefined ]
// 发生了回溯,开始 (\d{1,3}?)匹配了 1,后面发下 234 没有完还有一个5 为了完成任务,回退,重新尝试匹配 12
var regex = /^(\d{1,3}?)(\d{1,3})$/; // [ '12345', '12', '345', index: 0, input: '12345', groups: undefined ]
// console.log( string.match(regex) );
// 分支结构 回溯
var reg2 = /^(?:can|candy)$/
// 开始匹配can 发现 没有完成匹配(后面还有dy没有匹配完),回退;再用分支candy匹配
// console.log('candy'.match(reg2)); // [ 'candy', index: 0, input: 'candy', groups: undefined ]
// 避免回溯
// .*先是匹配所有 "abc"de,完了发现 后面跟着一个引号,回退到 abc ,发生回溯
// var reg3 = /".*"/;
//改为 非引号,匹配到abc 然后跟 引号 匹配完成
var reg3 = /"[^"]*"/;
console.log('"abc"de'.match(reg3));
表达式拆分
结构:字符字面量、字符组、量词、锚、分组、选择分支、反向引用
结构 说明
- 字面量 : 匹配一个具体字符,包括不用转义的和需要转义的。比如 a 匹配字符 "a",
又比如 \n 匹配换行符,又比如 . 匹配小数点。
- 字符组 : 匹配一个字符,可以是多种可能之一,比如 [0-9],表示匹配一个数字。
也有 \d 的简写形式。
另外还有反义字符组,表示可以是除了特定字符之外任何一个字符,比如 [^0-9],
表示一个非数字字符,也有 \D 的简写形式。
- 量 词 : 表示一个字符连续出现,比如 a{1,3} 表示 "a" 字符连续出现 3 次。
另外还有常见的简写形式,比如 a+ 表示 "a" 字符连续出现至少一次。
- 锚 : 匹配一个位置,而不是字符。比如 ^ 匹配字符串的开头,又比如 \b 匹配单词边界,
又比如 (?=\d) 表示数字前面的位置。
- 分 组 : 用括号表示一个整体,比如 (ab)+,表示 "ab" 两个字符连续出现多次,
也可以使用非捕获分组 (?:ab)+。
- 分 支 : 多个子表达式多选一,比如 abc|bcd,表达式匹配 "abc" 或者 "bcd" 字符子串。
反向引用,比如 \2,表示引用第 2 个分组。
操作符描述 操作符 优先级
- 转义符 \ 1
- 括号和方括号 (…)、(?:…)、(?=…)、(?!…)、[…] 2
- 量词限定符 {m}、{m,n}、{m,}、?、*、+ 3
- 位置和序列 ^、$、\元字符、一般字符 4
- 管道符(竖杠) | 5
// /ab?(c|de*)+|fg/
// 转移->括号->量词->位置和序列->分支
// (c|de*) 优先 ,c是一个 de* 另一个
// ab?(c|de*)+ 和 fg
//位置字符 ^ $ , 字符序列 abc 优先级高于 分支
// 过程是 开始 abc 结束 ; bcd结束
var reg1 = /^abc|bcd$/
// 开始 (abc 或者 bcd) 结束
var reg2 = /^(abc|bcd)$/
// console.log(reg1.test('abc'));
// console.log(reg2.test('bcd'));
// 量词连缀问题
// 每个字符是 a b c任意一个,字符串长度是3的倍数
// 直接写,报错,+前没有什么可重复的
// reg3 = /^[abc]{3}+$/ // 中括号[]优先选取一个,量词{} + 同时执行,报错
reg4 = /^([abc]{3})+$/ //([abc]{3})匹配三次先执行 + 表示3的倍数
// console.log(reg4.test('aacbbc'));
// 匹配元字符
// 只需要在第一个方括号转义即可,因为后面的方括号构不成字符组,正则不会引发歧义,自然不需要转义。
reg5 = /\[abc]/g
// console.log(reg5.test('[abc]'));
reg6 = /\{3.5}/g
// console.log(reg6.test('{3,5}'));
// 匹配身份证号
reg7 = /^(\d{15}|\d{17}[xX\d])$/
// 分支级别最低 分成两大组 \d{15} 和 \d{17}[xX\d]
//ipv4
reg8 = /^((0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])$/
// 先是括号内 ((0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])\.) (0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])
// 0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5] ==> 001 002 009 01 2 | 023 23 | 123 169 | 204 240 | 250 255
// 001.023.123.255
表达式的构建
步骤
- 编译;
- 设定起始位置;
- 尝试匹配;
- 匹配失败的话,从下一位开始继续第 3 步;
- 最终结果:匹配成功或失败。
// 判断字符串中是否存在
var str = 'adcsa?fdafc'
// console.log(str.indexOf('?'));
// console.log(str.search(/\?/));
// 截取字符串
var str2 = 'JavaScript';
// console.log(str2.substring(4));
// console.log(str2.match(/.{4}(.+)/)[1]);
// 匹配座机号
var str3 ='02788888888'
var str4 ='027-88888888'
var str5 = '(027)88888888'
// 区号两位或者3位 后面号码7或8位
var reg1 = /^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/
// console.log(reg1.test(str3));
// console.log(reg1.test(str4));
// console.log(reg1.test(str5));
// 匹配浮点数
var str6 = '1.23、 +1.23、-1.23 10、+10、-10 .2、+.2、-.2';
var reg2 = /[+-]?(\d+(\.\d+)?|(\.\d+))/g;
var reg3 = /[+-]?(\d+\.\d+|\d+|\.\d+)/g;
var reg4 = /^([+-]?(\d+\.\d+|\d+)|\.\d+)$/; // 不匹配 -.2 +.2
var reg5 = /[+-]?(\d+)?\.?\d+/g;
// console.log(str6.match(reg5));
// console.log(reg5.test(str6));
// 正则中带全局修饰符g的 ,匹配是从lastindex开始的,不带g匹配从0开始
var str7 = '123abc34def';
var reg6 = /\d+/
var reg7 = /\d+/g
// console.log(reg6.exec(str7)); // '123', index: 0, input: '123abc34def'
// console.log(reg6.exec(str7)); // '123', index: 0, input: '123abc34def'
// console.log(reg6.exec(str7)); // '123', index: 0, input: '123abc34def'
// console.log(reg7.exec(str7)); // '123', index: 0, input: '123abc34def'
// console.log(reg7.exec(str7)); // '34', index: 6, input: '123abc34def'
// console.log(reg7.exec(str7)); // null
// 具体的字符组代替 通配符,减少 回溯
var str8='123"abc"456';
var reg9 = /".*"/; // 多次回溯
var reg10 = /".*?"/ // 惰性匹配,开始匹配a,发现没有匹配完成 回退; 然后匹配 ab发现没有结束 回退 ;然后匹配abc; 回溯两次
var reg11 = /"[^"]*"/ //字符组没有回溯
// 使用非捕获类型分组
// 括号的作用之一是,可以捕获分组和分支里的数据。那么就需要内存来保存它们
var reg12 = /^[+-]?(\d+\.\d+|\d+|\.\d+)$/; // 用不上反向引用
var reg13 = /^[+-]?(?:\d+\.\d+|\d+|\.\d+)$/;
// 独立出确定字符
var reg14 = /A+/
// 比reg14更好,多确定了一个’A‘ 减少了第四步的执行, 加快判断是否匹配失败 提高效率
var reg15 = /AA*/
// 提取分支公共部分 这样做,可以减少匹配过程中可消除的重复。
var reg16 = /^abc|^cdf/
var reg17 = /^(?:abc|cdf)/
var reg18 = /this|that/
var reg19 = /th(?:is|at)/
// 减少分支的数量,缩小它们的范围
// 此时分支和量词产生的回溯的成本是不一样的。但这样优化后,可读性会降低的
var reg20 = /red|read/
var reg21 = /rea?d/
表达式编程
// 验证
var reg1 = /\d/;
var str1 = 'abc123';
var str2 = 'abc';
// console.log(str2.search(reg1)); //-1
// console.log(str1.search(reg1)); // 3
// 需要判断字符串中是否存在数字,返回布尔值,要用到 !!~
// 数字的按位取反不管正负 都等于 他的相反数 然后 -1
// ~5 相反数 -5 -1 = -6; -1的相反数1 -1 =0
// 所以 !!~-1 ==> !!0 ==> false
// 所以 !!~3 ==> !!-2 ==>true
// 判断是否存在改写为
// console.log(!!~str1.search(reg1)); //true
// console.log(!!~str2.search(reg1)); //false
// console.log(!!str1.match(reg1)); //true
// console.log(!!str2.match(reg1)); // false
// console.log(reg1.test(str1)); //true
// console.log(reg1.test(str2)); //false
// 切分
let str1='2017-05-20';
let str2='2017/05/20';
let str3='2017.05.20';
let reg1=/\D/g
// console.log(str1.split(reg1));
// console.log(str2.split(reg1));
// console.log(str3.split(reg1));
// 提取
let reg2 = /^(\d{4})\D(\d{2})\D(\d{2})$/
// console.log(str1.match(reg2));
// console.log(reg2.exec(str1));
// reg2.test(str1)
// str1.search(reg2);
// console.log(RegExp.$1,RegExp.$2,RegExp.$3);
let list = [];
str1.replace(reg2,function(a,b,c,d){
// console.log(a,b,c,d); //2017-05-20 2017 05 20
list.push(b,c,d)
})
// console.log(list);
// 替换
// console.log(str1.replace(/-/g,'/'));
// string实例4个,正则实例两个
// match和search接受字符串参数时,会把字符串转换为正则
// String#search
// String#split
// String#match
// String#replace
// RegExp#test
// RegExp#exec
// search查找字符串中任意字符,而不是字符串中的点
// console.log(str3.search('.')); //0
// console.log(str3.search('\\.')); // 4
// console.log(str3.search(/\./)); // 4
// 同理 match也是一样
// console.log(str3.match('.')); // [ '2', index: 0, input: '2017.05.20', groups: undefined ]
// console.log(str3.match('\\.')); // [ '.', index: 4, input: '2017.05.20', groups: undefined ]
// console.log(str3.match(/\./)); // [ '.', index: 4, input: '2017.05.20', groups: undefined ]
// console.log(str3.split('.')); // [ '2017', '05', '20' ]
// console.log(str3.replace('.','/')); // 2017/05.20
// match 返回结果的格式问题
let reg3 = /\b(\d+)\b/
let reg4 = /\b(\d+)\b/g
// 没有 g,返回的是标准匹配格式,即,数组的第一个元素是整体匹配的内容,接下来是分组捕获的内容,
// 然后是整体匹配的第一个下标,最后是输入的目标字符串。
// console.log(str3.match(reg3)); // [ '2017', '2017', index: 0, input: '2017.05.20', groups: undefined ]
// 有 g,返回的是所有匹配的内容。
// console.log(str3.match(reg4)); // [ '2017', '05', '20' ]
// 当没有匹配时,不管有无 g,都返回 null。
// console.log(str3.match(/\b(\d90)/)); // null
// console.log(str3.match(/\b(\d90)/g)); // null
// 比match更强大的exec
// console.log(reg4.exec(str3)); // [ '2017', '2017', index: 0, input: '2017.05.20', groups: undefined ]
// console.log(reg4.exec(str3)); // [ '05', '05', index: 5, input: '2017.05.20', groups: undefined ]
// console.log(reg4.exec(str3)); // [ '20', '20', index: 8, input: '2017.05.20', groups: undefined ]
// while(result=reg4.exec(str3)){ // reg4.lastIndex 表示下一次匹配开始的位置
// console.log(result,reg4.lastIndex);
// }
// 修饰符 g,对 exex 和 test 的影响
// 而正则实例的两个方法 exec、test,当正则是全局匹配时,每一次匹配完成后,都会修改 lastIndex
let reg5 = /a/g
let reg6 = /a/
// console.log(reg5.test('a'),reg5.lastIndex); // true 1
// console.log(reg5.test('aba'),reg5.lastIndex); // true 3
// console.log(reg5.test('ababc'),reg5.lastIndex); // false 0 从ababc的第四个b开始找a找不到
// 没有g都是从0开始匹配
// console.log(reg6.test('a'),reg6.lastIndex); // true 0
// split 相关注意事项
let str4 = 'html,css,javascript';
// 第二个参数表示 返回数组最大长度
// console.log(str4.split(/,/,2)); // [ 'html', 'css' ]
// 使用分组时,返回数组中包含分隔符
// console.log(str4.split(/(,)/)); // [ 'html', ',', 'css', ',', 'javascript' ]
// replace 是很强大的
// 第二参数是字符串时,可以匹配 $1-$99 表示分组捕获;$& 匹配到的子串文本;$` 匹配到子串左边;$' 匹配到子串右边; $$美元符
// console.log('abc 123'.replace(/[\w^\d]+/,'$&666')); // abc666 123
// console.log('abc 123'.replace(/\d+/,'$&666')); // abc 123666
// console.log('abc 123'.replace(/\d+/,'$`666')); // abc abc 666 : $`表示 123左边部分
// console.log('abc 123 def'.replace(/\d+/,"$'666")); // abc def666 def : $' 表示123右侧部分
// "2,3,5",变成 "5=2+3":
// console.log('2,3,5'.replace(/(\d)\,(\d)\,(\d)/,"$3=$1+$2")); // 5=2+3
// 把 "2,3,5",变成 "222,333,555"
// console.log('2,3,5'.replace(/\d+/g,"$&$&$&")); // 222,333,555
// 把 "2+3=5",变成 "2+3=2+3=5=5"
// console.log('2+3=5'.replace(/=/,"$&$`$&$'$&")); // 2+3=2+3=5=5
// 第二个参数是函数时 function (match, $1, $2, index, input) 匹配文本、第一个捕获分组、第二个捕获分组、捕获开始位置下标、输入文本
// 使用构造函数需要注意的问题
// 用构造函数会多写很多 \
let str5="2017-06-27 2017.06.27 2017/06/27"
let reg7 = /\d{4}(-|\.|\/)\d{2}\1\d{2}/g;
let reg8=new RegExp("\\d{4}(-\|\\.\|\\/)\\d{2}\\1\\d{2}","g")
// console.log(str5.match(reg8));
// 属性 i 忽略大小写;g 全局; m 多行;lastIndex 表示下一次匹配开始的位置 ; soucre 通过查看该属性,来确认构建出的正则到底是什么
var str6="heigh";
var reg9 = new RegExp("(^|\\s)"+str6+"(\\s|$)")
console.log(reg9.source); // (^|\s)heigh(\s|$)
// 构造函数属性
静态属性 描述 简写形式
- RegExp.input 最近一次目标字符串 RegExp["$_"]
- RegExp.lastMatch 最近一次匹配的文本 RegExp["$&"]
- RegExp.lastParen 最近一次捕获的文本 RegExp["$+"]
- RegExp.leftContext 目标字符串中lastMatch之前的文本 RegExp["$`"]
- RegExp.rightContext 目标字符串中lastMatch之后的文本 RegExp["$'"]
实例
function getClassNameList(clas) {
let list = [];
let elements = document.getElementsByTagName('*');
let reg = new RegExp("(^|\\s)" + clas + "(\\s|$)");
for (let index = 0; index < elements.length; index++) {
if (elements[index].className&®.test(elements[index].className)) {
list.push(elements[index])
}
}
return list
}
let els= getClassNameList('high');
els.forEach(e=>{
e.style.color="red"
})
// 封装一个对象用来判断是否是某种类型
let util={}
let typeStr = "String|Number|Boolean|Null|Undefined|Array|Function|Object|Date|Error|RegExp"
typeStr.split('|').forEach(e=>{
util['is'+e] = function(obj){
return Object.prototype.toString.call(obj) === "[object "+e+"]"
}
})
// console.log(util.isArray([1]));
// console.log(util.isString(''));
var readyRE = /complete|loaded|interactive/;
function ready (callback) {
if (readyRE.test(document.readyState) && document.body) {
callback()
}
else {
document.addEventListener(
'DOMContentLoaded',
function () {
callback()
},
false
);
}
};
ready(function () {
alert("加载完毕!")
});
let str1 = "a=1&b=2&a=3&b=4";
let reg1 = /([^=&]+)=([^&]*)/g;
// console.log(str1.match(reg1)); // [ 'a=1', 'b=2', 'a=3', 'b=4' ]
let keys = {}
str1.replace(reg1,function(a,b,c){
// console.log(a); // a=1 匹配到的文本
// console.log(b); // a 第一个捕获分组
// console.log(c); // 1 第二个捕获分组
keys[b] = (keys[b]?keys[b]+',':'')+c
})
// console.log(keys); { a: '1,3', b: '2,4' }
let res = []
for(key in keys){
res.push(key+'='+keys[key]);
}
console.log(res.join('&')); // a=1,3&b=2,4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
section {
display: flex;
flex-direction: column;
justify-content: space-around;
height: 300px;
padding: 0 200px;
}
section * {
min-height: 30px;
}
#err {
color: red;
}
#result {
line-height: 30px;
}
.info {
background: #00c5ff;
padding: 2px;
margin: 2px;
display: inline-block;
}
</style>
</head>
<body>
<section>
<div id="err"></div>
<input id="regex" placeholder="请输入正则表达式">
<input id="text" placeholder="请输入测试文本">
<button id="run">测试一下</button>
<div id="result"></div>
</section>
</body>
<script>
(function () {
// 获取相应dom元素
var regexInput = document.getElementById("regex");
var textInput = document.getElementById("text");
var runBtn = document.getElementById("run");
var errBox = document.getElementById("err");
var resultBox = document.getElementById("result");
// 绑定点击事件
runBtn.onclick = function () {
// 清除错误和结果
errBox.innerHTML = "";
resultBox.innerHTML = "";
// 获取正则和文本
var text = textInput.value;
var regex = regexInput.value;
if (regex == "") {
errBox.innerHTML = "请输入正则表达式";
} else if (text == "") {
errBox.innerHTML = "请输入测试文本";
} else {
regex = createRegex(regex);
if (!regex) return;
var result, results = [];
// 没有修饰符g的话,会死循环
if (regex.global) {
while (result = regex.exec(text)) {
results.push(result);
}
} else {
results.push(regex.exec(text));
}
if (results[0] == null) {
resultBox.innerHTML = "匹配到0个结果";
return;
}
// 倒序是有必要的
for (var i = results.length - 1; i >= 0; i--) {
var result = results[i];
var match = result[0];
var prefix = text.substr(0, result.index);
var suffix = text.substr(result.index + match.length);
text = prefix
+ '<span class="info">'
+ match
+ '</span>'
+ suffix;
}
resultBox.innerHTML = "匹配到" + results.length + "个结果:<br>" + text;
}
};
// 生成正则表达式,核心函数
function createRegex(regex) {
try {
if (regex[0] == "/") {
regex = regex.split("/");
regex.shift();
var flags = regex.pop();
regex = regex.join("/");
regex = new RegExp(regex, flags);
} else {
regex = new RegExp(regex, "g");
}
return regex;
} catch (e) {
errBox.innerHTML = "无效的正则表达式";
return false;
}
}
})();
</script>
</script>
</html>
常用手册
字面量
模式 说明
字母、数字 匹配字面量本身。比如 /f/,匹配字母 "f"。
\0 匹配 NUL 字符。
\t 匹配水平制表符。
\v 匹配垂直制表符。
\n 匹配换行符。
\r 匹配回车符。
\f 匹配换页符。
\xnn 匹配拉丁字符。比如 \xOA 等价于 \n。
\uxxxx 匹配 Unicode 字符。比如 \u2028 匹配行终止符,\u2029 匹配段终止符。
\cX 匹配 ctrl+X。比如 \cI 匹配 ctrl+I,等价于 \t。
[\b] 匹配 Backspace 键(特殊记忆)。
字符组
模式 说明
[abc] 匹配 "a"、"b"、"c" 其中任何一个字符。
[a-d1-4] 匹配 "a"、"b"、"c"、"d"、"1"、"2"、"3"、"4" 其中任何一个字符。
[^abc] 匹配除了 "a"、"b"、"c" 之外的任何一个字符。
[^a-d1-4] 匹配除了 "a"、"b"、"c"、"d"、"1"、"2"、"3"、"4" 之外的任何一个字符。
. 通配符,匹配除了少数字符(\n)之外的任意字符。
\d 匹配数字,等价于 [0-9]。
\D 匹配非数字,等价于 [^0-9]。
\w 匹配单词字符,等价于 [a-zA-Z0-9_]。
\W 匹配非单词字符,等价于 [^a-zA-Z0-9_]。
\s 匹配空白符,等价于 [ \t\v\n\r\f]。
\S 匹配非空白符,等价于 [^ \t\v\n\r\f]。
量词
模式 说明
{n,m} 连续出现 n 到 m 次。贪婪模式。
{n,} 至少连续出现 n 次。贪婪模式。
{n} 连续出现 n 次。贪婪模式。
? 等价于 {0,1}。贪婪模式。
+ 等价于 {1,}。贪婪模式。
* 等价于 {0,}。贪婪模式。
{n,m}? 连续出现 n 到 m 次。惰性模式。
{n,}? 至少连续出现 n 次。惰性模式。
{n}? 连续出现 n 次。惰性模式。
?? 等价于 {0,1}?。惰性模式。
+? 等价于 {1,}?。惰性模式。
*? 等价于 {0,}?。惰性模式。
位置
模式 说明
^ 匹配开头的位置,当正则有修饰符 m 时,表示匹配行开头位置。
$ 匹配结尾的位置,当正则有修饰符 m 时,表示匹配行结尾位置。
\b 匹配单词边界,即,\w 与 \W、^ 与 \w、\w 与 $ 之间的位置。
\B 匹配非单词边界,即,\w 与 \w、\W 与 \W、^ 与 \W,\W 与 $ 之间的位置。
(?=abc) 匹配 "abc" 前面的位置,即此位置后面匹配 "abc"。
(?!abc) 匹配非 "abc" 前面的位置,即此位置后面不匹配 "abc"。
括号的作用
模式 说明
(ab) 捕获型分组。把 "ab" 当成一个整体,比如 (ab)+ 表示 "ab" 至少连续出现一次。
(?:ab) 非捕获型分组。与 (ab) 的区别是,它不捕获数据。
(good|nice) 捕获型分支结构。匹配 "good" 或 "nice"。
(?:good|nice) 非捕获型分支结构。与 (good|nice) 的区别是,它不捕获数据。
\num 反向引用。 比如 \2,表示引用的是第二个括号里的捕获的数据。
修饰符
符号 说明
g 全局匹配,找到所有满足匹配的子串。
i 匹配过程中,忽略英文字母大小写。
m 多行匹配,把 ^ 和 $ 变成行开头和行结尾。
String相关实例方法
属性 方法作用说明
search 返回正则匹配到的第一个子串在目标字符串中的下标位置。
split 以正则匹配到的子串,对目标字符串进行切分。返回一个数组。
match 对目标字符串执行正则匹配操作,返回的匹配结果数组中包含具体的匹配信息。
replace 对目标字符串进行替换操作。正则是其第一个参数。返回替换后的字符串。
replace 第二个参数中的特殊字符
字符 说明
$1,$2,…,$99 匹配第 1-99 个分组里捕获的文本
$& 匹配到的子串文本
$ 匹配到的子串的左边文本 <br/> \$' 匹配到的子串的右边文本 <br/> \$$ 美元符号 <br/> RegExp相关实例方法 属性 方法作用说明 test 判断目标字符串中是否有满足正则匹配的子串。返回布尔值。 exec 比 match 更强大的正则匹配操作。返回结果与 match 一致。 RegExp静态属性 属性 方法作用说明 \$1,…,\$9 最近一次第 1-9 个分组捕获的数据。 input 最近一次目标字符串,可以简写成 $_ 。 lastMatch 最近一次匹配的文本,可以简写成 $& 。 lastParen 最近一次捕获的文本,可以简写成 $+ 。 leftContext 目标字符串中 lastMatch 之前的文本,可以简写成 $
。
rightContext 目标字符串中 lastMatch 之后的文本,可以简写成 $' 。
术语中英文对照表
正则表达式 regular expressions
字符组 character classes
反义字符组 negated character classes
范围表达式法 range expressions
元字符 metacharacters
通配符 wildcard character
换行符 newline charactor
回车符 carriage return character
水平制表符 tab character
垂直制表符 vertical tab charecter
换页符 form feed character
空白符 whitespace
段终止符 paragraph terminator
行终止符 line terminator
单词字符 word characters
非单词字符 non-word characters
数字字符 digits
非数字字符 non-digits
字母数字字符 alphanumeric characters
量词 quantifiers
贪婪量词 greedy quantifiers
惰性量词 lazy quantifiers
位置 positions
锚 anchors
行开头 beginning of a line
行结尾 end of a line
单词边界 word boundaries
非单词边界 non-word boundaries
向前查找 lookahead
正向向前查找 positive lookahead
负向向前查找 negative lookahead
向后查找 lookbehind
正向向后查找 positive lookbehind
负向向后查找 negative lookbehind
分组 groups
捕获分组 capturing groups
非捕获分组 non-capturing groups
分支结构 alternations
反向引用 back references
回溯 backtracks
运算符 operators
优先级 priority level
修饰符 flags
全局匹配修饰符 global flag
忽略大小写修饰符 ingnoreCase flag
多行匹配修饰符 multiline flag