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);  // &lt;div&gt;Blah blah blah&lt;/div&gt;

// 反转义
var htmlEntities = {
    nbsp: ' ',
    lt: '<',
    gt: '>',
    quot: '"',
    amp: '&',
    apos: '\''
};  
let resNs = '&lt;div&gt;Blah blah blah&lt;/div&gt;'.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

表达式的构建

步骤
  1. 编译;
  2. 设定起始位置;
  3. 尝试匹配;
  4. 匹配失败的话,从下一位开始继续第 3 步;
  5. 最终结果:匹配成功或失败。
// 判断字符串中是否存在
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&&reg.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
            

posted @ 2021-08-19 11:50  smartwange  阅读(512)  评论(0)    收藏  举报