正则

423 阅读9分钟

正则表达式(简写为 regexp) 用正则制定的规则,对字符串进行处理。如(查找 替换匹配某个字符串是 否符合规则等)。在 JS 中主要用正则表达式来处理字符串。

编程中的日常应用:

- 表单验证(验证用户填入的信息 邮箱、用户名、密码格式是否合法)
- 日期格式化(2019-01-02 => 2019/01/02)
- 查找匹配的关键词('hello2018 hello2019' => [2018, 2019])
- 对文本内容进行匹配替换

掌握了正则表达式,可能为你带来超乎想象的文本处理能力。有时只是一个简单的命令,就可以帮你处理所有文本数据。 其实像我们的文本编辑器、IDE 都支持使用正则查找关键词。

正则表达式语法


  • 字面量方式
// 在两个斜杠之间的字符内容称为元字符 /元字符/
const reg = /\d/igm // \d是元字符代表[0-9]任意一位数 igm是修饰符
  • 实例化方式
// 实例化方式边界不需要加斜杠 对于特殊元字符需要加上转义斜杠
const reg = new RegExp('\\d', 'igm')

// 可以拼接变量
const cn = 'china'
const reg1 = new RegExp(`${cn}\\d+`)
console.log(reg1) // /china\d+/

正则表达式中的元字符和修饰符


  • 每一个正则表达式都是由元字符和修饰符组成的
// \d是特殊元字符 代表[0-9]中任意一个数字 igm是修饰符
const reg1 = /\d/igm

// 实例化方式边界不需要加斜杠 对于特殊元字符前面需要加上转义斜杠
const reg = new RegExp('\\d', 'igm')

正则匹配

在 RegExp 原型有一个 test 方法,用来验证字符内容是否符合正则。定义的每个正则都是 RegExp 类的实例。

语法:

reg.test('字符内容')

const reg = /\d/
reg.test('1') // true

修饰符

  • i ignoreCase 忽略大小写
  • g global 全局匹配
  • m multiline 多行匹配

特殊元字符

在正则中具有特殊意义的字符

\ 转义字符

\d 匹配 0-9 的数字 包含 0 和 9 相当于[0-9]

\D 除了 0-9 的任意字符

\w 匹配数字、字母、下划线 相当于[0-9a-zA-Z_]

\W 匹配除了数字、字母、下划线以外的其他字符,相当于[^0-9a-za-z_]

\s 匹配空白符(空格\s 换行\r\n 制表符 tab)

\S 匹配除了空白符(空格 换行 制表符)以外的字符

\b 匹配单词边界 'hello world'

\n 匹配换行符

^ 匹配字符串的开始位置(以某个元字符作为开头)

$ 匹配字符串的结束位置(以某个元字符作为结尾)

. 匹配除了\n 以外的任意字符(在这里默认不是小数点的意思 可以转义为小数点 .)

console.log(/./.test('\n')) // false
console.log(/./.test('1')) // true
console.log(/./.test('w')) // true
console.log(/./.test('_')) // true
console.log(/./.test('.')) // true

// . 转义为普通小数点
console.log(/./.test('.')) // true
console.log(/./.test('1')) // false
console.log(/./.test('w')) // false

其他元字符

x|y x 或者 y

[xyz] 匹配 xyz 中的任意一个字符

[^xyz] 匹配除了 xyz 以外的任意一个字符

[a-z] 匹配 a 到 z 中的任意一个字符 [0-9] === \d

[^a-z] 匹配除了 a 到 z 以外的任意一个字符 [^0-9] === \D

() 分组捕获 括号中的内容单独捕获一次

(?😃 只匹配不捕获

(?=) 正向预查

(?!) 负向预查

量词元字符

? 出现 0 次或 1 一次(最多出现一次 可有可无)

* 代表出现 0 到多次,相当于{0,}

+ 代表出现 1 到多次(至少出现一次),相当于{1,}

{n} 连续出现 n 次

{n,} 连续出现 n 到多次

{n,m} 连续出现 n 都 m 次(最少 n 次 最多 m 次)

普通元字符

/abc/

    // 正则:由元字符和修饰符组成 处理字符串 匹配验证 捕获 的规则
    // RegExp
    // 元字符:/\dasc/ 两个斜杠之间的就是元字符 特殊元字符 量词元字符 普通元字符
    // 修饰符 /sdfds/igm

    // 1.特殊元字符
    // \ 转义符 转换为本来意义
    // . 任意字符 除了\n(换行符) /./ /\./
    // \n 匹配换行符
    // \d 0-9之间的一个数字  /\d/ [0-9]
    // \D 除了\d 除的了0-9数字以外   /\D/ [^0-9]
    // \b 匹配边界 '123 a12' /\b\d/ /\d\b/
    // \B 非边界  '123 a12' /\B\d/匹配的是不以数字作为开头的边界 /\d\B/
    // \w 数字0-9字母a-z A-Z下划线_  等价于 [0-9a-zA-Z_]
    // \W  除了\w 除了数字0-9字母a-z A-Z下划线_以外的字符
    // \s 空格符
    // \S 非空格
    // [xyz] x或者y或者z 中的一个 '1x2y'
    // [^xyz] 除了x或者y或者z中的 其他字符 'x123'
    // [a-z] 匹配a-z中任意一个小写字母  'a'
    // [^a-z] 除了a-z中任意一个字符
    // x|y|z x或者y或者z
    // () 分组 改变优先级 划分小正则 分组引用
    // ^ 以什么开头 /^\d/ '12' '1a'
    // $ 以什么结尾 /\d$/ 'a2'
    // ?: 只匹配不捕获
    // ?= 正向预查
    // ?! 负向预查

    // 2.量词元字符
    // ? 出现0到1次(可有可无) /a?/ '1a23'
    // * 出现0到多次  /a*/ '12aaaaaaaa312'
    // + 出现1到多次 至少出现1次 /a+/ '123aaaaa12'
    // {n} 限定出现n次 匹配只能出现n次  /a{2}/ '1aa1'
    // {n,} 限定出现n到多次 至少出现n次 /a{2,}/ '1aaaaaa1'
    // {n,m} 限定出现n到m次 /a{2, 5}/ '113aaa5' 出现2-5次 2 3 4 5

    // 3.普通元字符
    /abcd/

    // 修饰符
    // i ignoreCase 忽略大小写  /[a-z]/i  'a' 'A'
    // g global 全局 /[a-z]/g  's'
    // m multiline 逐行匹配  /^\d/ '123123'

正则中括号

 [18] 不识别多位数 1 或者 8
 
 [12-68] 1或者 [2-6] 或者8
 
 [] 中括号里 部分元字符代表本意 [.] [?] [+] [*]
 
 [\d] [\s] [\w] 代表是还是原本特殊的意义

[]中不识别多位数

  // [18] 不识别多位数 1 或者 8<br>
  let reg = /^[18]$/<br>
  console.log(reg.test('1')) // true<br>
  console.log(reg.test('8')) // true<br>
  console.log(reg.test('a')) // false<br>

[12-68] 1 或者 [2-6] 或者 8

  let reg = /^ [12-68]$ / <br>
  console.log(reg.test('1')) // true <br>
  console.log(reg.test('2')) // true <br>
  console.log(reg.test('6')) // true <br>
  console.log(reg.test('8')) // true <br>
  console.log(reg.test('9')) // false <br>

[] 中括号里部分元字符 代表普通元字符

// [\d] [\s] [\w] 代表是还是原本的特殊意义
// [\d] [0-9]

let reg = /[\d]/
reg.test('1') // true

// 代表普通元字符 [.] [?] [+] [*]
let reg = /[\w]/
console.log(reg.test('1'))

let reg = /[*]/
console.log(reg.test('*')) // true
let reg = /[+]/
console.log(reg.test('+')) // true
let reg = /[\d]/
console.log(reg.test('2')) // true

正则匹配和捕获

  • 匹配:验证字符内容是否符合正则规则 返回 true 或 false
  • 捕获: 将匹配(符合正则规则)的内容 作为返回值返回给我们

RegExp 原型上的两个方法

// test 检测字符串内容是否符合(匹配)正则规则。返回值: boolean值<br>
RegExp.prototype.test('字符内容')

// exec 将匹配的内容,捕获出来返回给我们。返回值:null或数组形式<br>
RegExp.prototype.exec('字符内容')

test

  • reg.test('字符内容')

/\d/.test('1') // true

exec

reg.exec('字符内容')

/**
  ["1", index: 0, input: "123", groups: undefined]
  1.数组中从第一项开始时 是正则捕获到的内容,如果有分组继续往后排
  2.index 正则捕获内容的起始索引位置
  3.input 原始字符串
  4.groups 捕获命名分组内容
*/

// ["1", index: 0, input: "123", groups: undefined]
/\d/.exec('123')

命名分组

  let reg = /(?<num>\d+)/
  reg.exec('hello2019')

lastIndex

lastIndex 下一次开始匹配或捕获的起始索引位置

关于[]细节问题

// /[81]/ 不能识别多位数 看作是8或者1
// [a-z] a到z 26个小写字母
// [13-56] 1 或者 3到5 或者6
// []中括号里部分元字符代表的是本身意义 [+] '+' [?] '?' [.] '.'
// [\d] 依然代表的是 0-9中的一个数字

正则应用


验证手机号

  // 2. 手机号 188 176 138 11位数 开头只能是1
  var reg = /^1(88|76|38)\d{8}$/; // ^$只能是11位数 不能有其他字符
  reg.test('17645678999')
  reg.test('18845678999')
  reg.test('13845678999')

验证有效数字

  let reg = /^[+-]?(\d|[1-9]\d)(\.\d+)?$/
  console.log(reg.test('1'))
  console.log(reg.test('-21'))
  console.log(reg.test('1.1'))
  console.log(reg.test('0'))

匹配某个范围内的数字

  // 28-66
  let reg = /^(2[89]|[2-5]\d|6[0-6])$/
  console.log(reg.test('17'))
  console.log(reg.test('18'))
  console.log(reg.test('38'))
  console.log(reg.test('65'))
  console.log(reg.test('66'))

中文姓名

  let reg = /^[\u4E00-\u9FA5]{2,10}$/
  console.log(reg.test('adfs'))
  console.log(reg.test('文利'))

验证邮箱

  // 雅虎邮箱  XXXXXX@yahoo.com.cn
  // 雅虎邮箱  XXXXXX@yahoo.cn
  // Google  XXXXX@gmail.com
  // QQ     XXXXX@qq.com

  // 102495553@qq.com
  // brolly_0204@yahoo.com.cn
  // wenli-china@gmail.com

  let reg = /^[a-zA-Z0-9\u4E00-\u9FA5]+[a-zA-Z0-9\u4E00-\u9FA5_-]*@[a-zA-Z0-9_]+(\.[a-zA-Z0-9]+){1,2}$/
  console.log(reg.test('102495553@qq.com'))
  console.log(reg.test('brolly_0204@yahoo.com.cn'))
  console.log(reg.test('爱丽丝-china@yahoo.com.cn'))
  console.log(reg.test('wenli-china@gmail.com'))
  console.log(reg.test('_wenli-china@gmail.com')) // false
  console.log(reg.test('wenli-china@gmail')) // false

数据类型检测

  // "[Object xxx]"
  let reg = /\[Object (\w+)\]/
  console.log(reg.exec('[object Array]')[1])

  // 数据类型检测
  Object.isType = function (val) {
    let reg = /^\[object (\w+)\]$/
    let res = Object.prototype.toString.call(val)
    return reg.exec(res)[1].toLowerCase()
  }
  console.log(Object.isType(1))
  console.log(Object.isType(null))

密码验证

  // 包含 数字 字母大小写
  // let reg = /^(?!([a-zA-Z]+|\d+)$)[a-zA-Z\d]{8,15}$/
  let reg = /^(?!([a-zA-Z]+|[a-z\d]+|[A-Z\d]+)$)[a-zA-Z\d]{8,15}$/
  console.log(reg.test('lolABC123'))

字符串方法


match

  // exec match
  // 1.exec是正则捕获方法 match是字符串捕获方法
  // 2.正则没有取消懒惰性时候 exec 和match 捕获到的内容 是一模一样的
  // 3.如果取消了懒惰性 exec需要捕获多次才能捕获完,match可以一次性捕获完 将捕获到的内容放在一个数组里
  // 4.分组捕获区别
  // (1) 如果是全局匹配加了g Match是无法捕获到分组
  // (2) 如果没有加g Match和exec 捕获到的内容 一样 也能把分组捕获到

  // match 里面也是 调用了exec
  String.prototype.myMatch = function (reg) {
      var res = reg.exec(this);
      if (reg.global) { // 是否取消懒惰性
          var arr = [];
          while (res) {
              arr.push(res[0]); // 将捕获到的添加到数组里 最后一次性返回
              res = reg.exec(this);
          }
          return arr.length ? arr : null; // 如果全局匹配 没有捕获到应该返回null
      }
      return res;
  };
  console.log(str.myMatch(reg));

正则属性


  /**
   * 正则实例属性
   * flags: 当前正则的修饰符
   * global: 是否有g修饰符(是否全局匹配)truefalse 无
   * ignoreCase: 是否有i修饰符 (是否忽略大小写) truefalse 无
   * multiline: 是否有m修饰符 (是否逐行匹配) truefalse 无
   * source: 正则的元字符内容
   */

分组


1.分组捕获

  // 1.分组捕获 将大正则划分为小正则 对大正则捕获到的内容进一步进行捕获 放到数组里
  var str = '{10}11';
  var reg = /\{(\d+)\}/;
  console.log(reg.exec(str)); // ["{10}", "10", index: 0, input: "{10}11"]

2.改变优先级

 // 2.改变优先级
  var reg = /^10|20$/;
  console.log(reg.test('10adf'));
  console.log(reg.test('adf20'));
  console.log(reg.test('10adf20'));

  var reg = /^(10|20)$/; // 限定了 只能是10或者20中的一个
  console.log(reg.test('10'));
  console.log(reg.test('20'));

3.分组引用

  // 3.分组引用 (确保分组已经存在 在获取分组引用 否则分组引用操作被忽略)
  var reg = /([a-z])([a-z])\1\2/; // 'abab'
  var reg = /([a-z])([a-z])\2\1/; // 'abba'
  var reg = /([a-z])\1([a-z])\2/; // 'aabb'
  var reg = /([a-z])\1([a-z])\2/; // 'aabb'
  var reg = /\1(\d)/; // \1要是再第一个分组前面使用 会被忽略掉
  console.log(reg.exec('1'));
  var reg = /([a-z])\1([a-z])\2/; // 'aabb'
  console.log(reg.test('aacc'));
  console.log(reg.test('ddff'));

问号


 /**
   * ?
   * 1.量词元字符出现0到1次
   * 2.?: 取消分组捕获 只匹配不捕获
   * 3.?放在量词元字符后面取消贪婪性 取消贪婪性 就按最短匹配
   * 4.?= 正向预查 一个条件 把条件写在分组(?=1) 不会对它进行分组捕获
   * 5.?! 反向预查 一个条件 把条件写在分组(?!1) 不会对它进行分组捕获
   */

取消贪婪性

    // 贪婪性 按照最长匹配 能多匹配就多匹配
    var str = 'h12345243';
    //    var reg = /\d+/; // + 等价于 {1,} 最短匹配1 最长不限
    //    console.log(reg.exec(str));

    //    var reg = /\d{2,4}/; 按最长匹配
    //    console.log(reg.exec(str)); // '1234'

    //    var reg = /\d{2,4}?/; //   取消贪婪性 就按最短匹配
    //    console.log(reg.exec(str)); // '12'

取消分组捕获

    // 默认情况只要你进行分组 捕获的时候 都会进行分组捕获
    // ?: 取消分组捕获 写在分组的最前面 只匹配该分组 不会进行分组捕获
    var reg1 = /^[+-]?(?:\d|[1-9]\d+)(?:\.\d+)?$/g;
    console.log(reg1.exec('-123.666'));

正向预查和负向预查

    //    正向预查 限定条件
    //    var reg = /[a-z](?=3|4)/; // 捕获的是字母后面跟着3或4的那个字母
    //    console.log(reg.exec('a3'));
    //    console.log(reg.exec('b4'));
    //    console.log(reg.exec('c3'));
    //    console.log(reg.exec('d6'));


    // 反向预查 排除条件

    //    var reg = /[a-z](?!3|4)/; // 捕获的是字母后面跟着不是3或4的那个字母
    //    console.log(reg.exec('a3'));
    //    console.log(reg.exec('b4'));
    //    console.log(reg.exec('c3'));
    //    console.log(reg.exec('d6'));

    //    var reg1 = /[a-z](?!3|4)/g;
    //    var str = 'a3b4c6h7';
    //    console.log(str.match(reg1));


    //    var reg = /^(?=3)\d$/; // 匹配的一位数只能是3
    //    console.log(reg.test('3'));
    //    console.log(reg.test('4'));
    //    console.log(reg.test('5'));

    //    var reg = /^((?=3)\d)+$/; // 出现的纯数字 必须都是3
    //    console.log(reg.test('3'));
    //    console.log(reg.test('333333'));
    //    console.log(reg.test('34567'));
    //    console.log(reg.test('33345'));

    // 匹配没有4的手机号
    let reg = /^1((?!4)\d){10}$/
    console.log(reg.test('15311199201'))

    //    var reg = /^(?!3)\d$/; // 匹配的一位数不能是3
    //    console.log(reg.test('3')); // false
    //    console.log(reg.test('4')); // true
    //    console.log(reg.test('5')); // true

    //    var reg = /^((?!3)\d)+$/; // 出现的纯数字 不能有3
    //    console.log(reg.test('3'));
    //    console.log(reg.test('4568'));
    //    console.log(reg.test('4567'));
    //    console.log(reg.test('33345'));

    //    var reg = /^(?!a)[a-z]$/; // 限定后面的范围a-z 出现的一个字母不能是a
    //    console.log(reg.test('a'));
    //    console.log(reg.test('b'));
    //    console.log(reg.test('v'));

replace


交换字符串中的两个单词

var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newstr = str.replace(re, "$2, $1");

  //"5=a,6=b,7=c"换成"a=5,b=6,c=7"
  var str="5=a,6=b,7=c";
  str=str.replace(/(\d+)=(\w)/g,"$2=$1");
  console.log(str);

ES6 模板字符串简单实现

  let name = 'wenli'
  let country = 'china'

  let str = `my name is ${name}, I like ${country}`

  str = str.replace(/${(.*)}/, (a, b) => {
    return eval(b)
  })
  console.log(str)

vue 模板数据简单实现

  let data = {
    title: 'hello zhufeng'
  }
  let str = '<h3>{{ title }}</h3>'

  let reg = /{{(.*)}}/
  str = str.replace(reg, function(a, b) {
    return data[b.trim()]
  })
  console.log(str)
  //    console.log(document.body.innerHTML);
  //    console.log(oText.innerHTML);
  //    var mess = 'hello world!';
  //    var say = ' beijinghuanyingni';
  //    oText.innerHTML = oText.innerHTML.replace(/\{\{(.+?)\}\}/g, function (a, b) {
  //         console.log(arguments);
  //         return eval(b)
  //    });


  // replace 支持正则
  //    var str = 'hh7h8';
  //    str = str.replace(/1/g, '2');
  //    str = str.replace(/\d/g, function (a) {
  //        console.log(arguments);
  //        // 第一个参数 匹配到的内容
  //        // 第二个参数 捕获到的索引位置
  //        // 第三个原始字符串
  ////        return 2 * arguments[0]
  //        console.log(a);
  //        return 2 * a
  //    });
  //    console.log(str);

  //    var str = '{01} -- {02} -- {03} -- {04}';

  //    var reg = /\{(\d)(\d)\}/g;
  //    str = str.replace(reg, function (a, b, c) { // 先把根据规则捕获 然后再替换
  ////        console.log(arguments);
  ////        console.log(b);
  ////        通过形参来得到捕获到的内容
  //
  //        // 第一项是大正则捕获到内容
  //        // 从第二项开始是分组捕获到的内容
  //        // 捕获到的索引位置
  //        // 最后一个原始字符串
  //        return c + '' + b // 返回值 替换大正则捕获到的内容
  //    });
  //    console.log(str);

  //    str = str.replace(reg, '$2$1');  // $1第一个分组里捕获的内容$1-9
  //    console.log(str);

  //    var str = 'zhufeng123zhufeng666';
  //    var reg = /(\d+)/g;
  //
  //    console.log(reg.exec(str)); // ["123", "123", index: 7, input: "zhufeng123zhufeng666"]
  //    console.log(reg.exec(str)); // ["666", "666", index: 17, input: "zhufeng123zhufeng666"]
  //    console.log(RegExp.$1); // 获取到最近一次正则捕获到的分组内容 $1-$9


  // 2017-01-01 18:00:40 => 2017年01月01日 18时00分40秒
  // 1.方式一
  //    var str = '2018-05-12 18:00:40';
  //    var reg = /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/;
  //   str = str.replace(reg, function (a, n1, n2, n3, n4, n5, n6) {
  //        console.log(arguments);
  //        return n1 + '年' + n2 + '月' + n3 + '日 ' + n4 + '时' + n5 + '分' + n6 + '秒'
  //    })
  //    console.log(str);
  //    str = str.replace(reg, '$1年$2月$3日 $4时$5分$6秒');
  //    console.log(str);
  //

  // 2. 方式二
  //    var time = ['年', '月', '日', '时', '分', '秒'];
  //    var n = 0; // 记录索引
  //    var reg = /(\d+)[:-]?/g;
  //    var str = '2018-05-12 18:00:40';
  //    str = str.replace(reg, function (a, b) {
  //         // 2018- 2018
  ////        console.log(b + time[n++]); // 2018 + time[0] 2018年
  //        return b + time[n++];
  //    });
  //    console.log(str);

  // 3.方式三
  //    var time = ['年', '月', '日', '时', '分', '秒'];
  //    var n = 0; // 记录索引
  //    var str = '2018-05-12 18:00:40';
  ////    str.split(/[- :]/) // split 支持正则
  ////    console.log(str.split(/ /));
  ////    console.log(str.split(/\s/));
  //
  //// console.log(str.split(/[- :]/)); // ["2018", "05", "12", "18", "00", "40"]
  //   var arr = str.split(/[- :]/);
  //   str = str.replace(/\d+[-:]?/g, function () {
  ////       2018- => arr[0]+''+time[0]   05- => arr[1]+ '' +time[1]
  //       var str2 = arr[n] + '' + time[n];
  //       n++;
  //       return str2;
  //   });
  //   console.log(str);

  // 4.模板引擎
  //    2017-01-01 18:00:40 => 2017年01月01日 18时00分40秒
  //    var str = '2018-05-12 18:00:40';
  //    var tempStr = '{0}年{1}月{2}日 {3}时{4}分{5}秒'; // 模板字符串
  //    var arr = str.split(/[: -]/); //  ["2018", "05", "12", "18", "00", "40"]
  //    //    console.log(arr);
  //    str = tempStr.replace(/\{(\d+)\}/g, function (a, b) {
  //        // arr[0] => {0} arr[1] => {1} arr[2] => {2}
  //        return arr[b];
  //    });
  //    console.log(str);


  //
  //    var htmlStr = 'https://www.baidu.com/s?wd=123&id=28&name1=zhufeng';
  //
  //    var htmlStr2 = 'https://www.baidu.com/s?wd=%E7%99%BE%E5%BA%A6&rsv_spt=1&rsv_iqid=0xb67cb0840000f3bc&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_enter=0&oq=vue&rsv_t=6babjh9kMd3aQtUraNwWM0bfzC5lnPlVkwqWVpOc2Ma898jqbZz9%2Byn76adAkylJ47pg&rsv_pq=ca645c620000ffb4';
  // {wd: 123, id: 38, name: zhufeng}

  //    var reg = /([\w-]+)=([\w-]+)/g;
  //    var obj = {};
  //    htmlStr.replace(reg, function (a, b, c) {
  ////        console.log(arguments);
  //        obj[b] = c;
  //    });
  //    console.log(obj);

  //    var reg = /([^?&=]+)=([^?&=]+)/g;
  //    var obj = {};
  //    htmlStr.replace(reg, function () {
  //        obj[arguments[1]] = arguments[2];
  //    });
  //    console.log(obj);

  //?wd=123&id=28&name1=zhufeng';
  //var str3 = '?wd=123&id=28&name1=zhufeng';
  //    var reg = /[^?&]+/g;
  //console.log(reg.exec(str3)); // "wd=123",
  //console.log(reg.exec(str3)); // id=28
  //console.log(reg.exec(str3)); // name1=zhufeng


  //// 处理查询字符串
  //    function getUrlParam(url) {
  //        var obj = {};
  //        var reg = /([^?&=]+)=([^?&=]+)/g;
  //        url.replace(reg, function () {
  //            obj[arguments[1]] = arguments[2]
  //        });
  //        return obj;
  //    }
  //console.log(getUrlParam(htmlStr));
  //console.log(getUrlParam(htmlStr2));

  // 去除首尾空格
  //    var str = ' class1  class2    ';
  //    var reg = /^\s+|\s+$/g;
  //    var reg = /^ +| +$/g;
  //    str = str.replace(reg,'');
  //    console.log(str);
  //console.log(str.trim());
  //    var str2 = str.trim(); // 自带的去除首尾空格
  //    console.log(str2);
  //
  //    String.prototype.myTrim = function () {
  //        var reg = /^\s+|\s+$/g;
  //        return this.replace(reg, '');
  //    };
  //
  //    var str3 = str.myTrim();


  // 千分符  2121345465 => 2,121,345,465

  // 1
  //    var str = '2121345465';
  ////    console.log(str.split('').reverse().join('')); // 5645431212
  //    var str2 = str.split('').reverse().join(''); // 5645431212
  //
  //    var reg = /(\d{3})/g;
  ////    str2 = str2.replace(reg, function () {
  ////        console.log(arguments);
  ////        return arguments[0] + ','
  ////    });
  //    str2 = str2.replace(reg, '$1,');
  //    console.log(str2.split('').reverse().join('')); // 2,121,345,465

  // 2正向预查
  var str = '2121345465.12'; // 2,121,345,465.12
  var reg = /(\d)(?=(\d{3})+(\.\d+|$))/g;
  //   str = str.replace(reg, function () { // 三个数字为一组
  ////       console.log(arguments); // 2 121 345 465 三组
  ////       console.log(arguments); // 1 345 465 两组
  ////       console.log(arguments); // 5 465 一组
  //        return arguments[0] + ',';
  //   });
  //    console.log(str);

  str = str.replace(reg, '$1,');
  console.log(str);

  // 统计字符串中字母重复出现次数
  let str = 'asdlfkj;;kajsd66sadff1233132'
  str = Array.from(str).sort().join('')
  
  let obj = {}
  str.replace(/([a-zA-Z])\1*/g, a => {
    obj[a[0]] = a.length
  })
  console.log(obj) // {a: 3, d: 3, f: 3, j: 2, k: 2, …}

  // 每个单词首字母大写
  let str = 'my name is brolly, hello world!'
  let str2 = str.replace(/\b([a-zA-Z])/g, a => a.toUpperCase())
  console.log(str2) // My Name Is Brolly, Hello World!

----------------------------------------------------------------------------------------------------------------
参考文章&&强烈推荐:布罗利