CruxF / Blog

个人博客,记载学习的点点滴滴,怕什么技术无穷,进一寸有一寸的欢喜:sparkles:
63 stars 19 forks source link

JavaScript正则表达式 #3

Open CruxF opened 6 years ago

CruxF commented 6 years ago

一、前言

该博文源自慕课网的《JavaScript正则表达式》课程。老师讲的生动有趣,由浅入深,是一门好课程。为了让自己更好记忆和继续深究正则表达式,因此写下该篇博文。下面推荐两个实用的在线网站: 正则表达式工具 代码及时响应在线网站

二、实例化正则对象

在JavaScript中,一共有两种方法实例化正则对象,下面请看具体的方法。

1、 字面量:var reg = /\bis\b/g; 【注意】 \b代表单词边界,g代表全文进行匹配。如果没有\b和g,会怎么样呢?请动手分别进行测试一下,下面给出测试模板,内容可自行更改。 测试:'he is a boy,This is a dog'.replace(reg,'IS');

2、 构造函数:var reg = new RegExp('\\bis\\b','g'); 【注意】 在构造函数中,我们需要\来进行转义。 测试:'he is a boy,This is a dog'.replace(reg,'IS');

三、修饰符

在JavaScript正则表达式中,一共有三种修饰符,分别是一下三种。 1、 g:global 全文搜索,假如不添加的话,那么搜索到第一个匹配即停止; 测试:'He is a boy,she is here?'.replace(/\bis\b/g,'0');

2、 i:ignore case 忽略大小写,默认大小写敏感; 测试:'He is a boy,she IS here?'.replace(/\bis\b/gi,'0');

3、 m:multiple lines 多行搜索。 测试:'@123\n@234\n@345'.replace(/^@\d/gm,'Q');

四、元字符

JavaScript正则表达式中,元字符非常之多,下面我们一起来耐心看看。

1、 \s:匹配单个空格,等同于[\f\n\r\t\v];而\S则恰恰相反,它匹配的是非空格字符。

测试:/\s.+/.exec('This is a test String.'); 【分析】 其中.含义是除了回车符和换行符之外的所有字符,+含义是出现一次或多次(至少出现一次),exec() 方法用于检索字符串中的正则表达式的匹配。假如有点晕,再来看看下面的栗子

var regs = /\s.+/
var str = "this is dog stil here"
// thishaha
 console.log(str.replace(regs,"haha"))

【应用场景】 匹配任意空或空白字符,如果你什么也没输入,或输入的只有空格、回车、换行等字符,则匹配成功。这样就可以验证用户是否正确输入内容了。 【用法】

var  reg=/^\s*$/;
if(reg.test(value)){
  alert('请输入有效值');
  return false;
}

【分析】 其中^含义是以什么为开始,*含义是出现零次或多次(任意次),$含义是以什么为结束,test() 方法用于检测一个字符串是否匹配某个模式.

2、 \w:表示单词字符,等同于字符集合[a-zA-Z0-9];而\W表示非单词字符,等效于[^a-zA-Z0-9]。

var reg = /\w+/;
var str='fengxiong';
alert(reg.exec(str));

【分析】 返回完整的fengxiong字符串,因为所有字符都是单词字符。

var reg = /\w+/;
var str='.className';
alert(reg.exec(str));

【分析】 结果显示匹配了字符串中的className,只有第一个“.”唯一的非单词字符没有匹配。

var reg = /\w+/;
var str='正则教程';
alert(reg.exec(str));

【分析】 试图用单词字符去匹配中文自然行不通了,返回 null。

var reg = /\W+/;
var str='正则教程';
alert(reg.exec(str));

【分析】 返回完整的字符串,因为,中文算作是非单词字符。

3、其他元字符 \f:匹配换页符; \n:匹配换行符; \r:匹配回车符; \t:匹配制表符; \v:匹配垂直制表符; \d:匹配数字; \D:匹配非数字; \b:匹配单词边界; \B:匹配非单词边界

来个测试题:将符合一个ab+数字+任意字符的字符串代替为B。 答案:'ab32432dab2,'.replace(/ab\d./g,'B');

五、重要元字符

1、^: 可以用来创建反向类/负向类,也就是不属于某类的内容,比如: 'a1b2c3d4'.replace(/[^abc]/g,'X');

又有以什么为开头的含义,比如: '1 fafs'.replace(/^\d\s/g,'Q');

2、[ ] 可以用来构建一个简单的类,也就是几个字符归纳为集合,比如: 'a1b2c3d4'.replace(/[abc]/g,'X');

可以使用[a-z]来连接两个字符表示从a到z的任意字符,比如: 'a1b2d3x4z9'.replace(/[a-z]/g,'A');

在[]组成的类内部是可以连写的,比如: 'a1b2d3x4z9B7A3N4M8'.replace(/[a-zA-Z]/g,'J');

如何在[]把-给算上呢?其实只要把-加在后面即可,比如: '2018-01-14'.replace(/[0-9-]/g,'A');

六、量词

?:出现零次或一次(最多出现一次); +:出现一次或多次(至少出现一次); *:出现零次或多次(任意次); {n}:出现n次; {n,m}:出现n到m次; {n,}:至少出现n次。

八、分组

1、使用()可以达到分组的功能,使用量词作用于分组,比如: 'a1b2c3d4'.replace(/([a-z]\d){3}/g,'X'); 'BoyGirl'.replace(/Boy|Girl/g,'X'); 'BoyGirlBoyBorl'.replace(/Boy(Gi|Bo)rl/g,'X');

2、分组的反向引用,比如,将2018-01-14 转换为 01/14/2018,对比下面两段代码的结果: '2018-01-14'.replace(/\d{4}-\d{2}-\d{2}/g,'$2/$3/$1'); '2018-01-14'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'$2/$3/$1');

八、贪婪模式与非贪婪模式

1、贪婪模式:尽可能多的匹配,比如: '12345678'.replace(/\d{3,6}/g,'X');

2、非贪婪模式:让正则表达式尽可能少的匹配,也就是说一旦成功匹配则不再继续尝试,比如: '12345678'.replace(/\d{3,6}?/g,'X');

九、正则表达式训练营

1、用正则匹配手机号码

function tele(tel) {
  if (tel.search(/^1[34578]\d{9}$/g) > -1) {
    console.log("1");
  } else {
    console.log("0");
  }
}
tele("13456799014");

【分析】 寻找以13、14、15、17或18开头,以9个数字结尾的字符,找到了就返回1,失败就返回0。search()方法去匹配字符串,如果匹配成功,就返回匹配成功的位置,如果匹配失败就返回-1

还有一种更加简便的方法:

function tele(tel) {
  return /^1[34578]\d{9}$/g.test(tel);
}
console.log(tele("13456799014"));

【分析】 test()方法的返回值是布尔值,通过该值可以匹配字符串中是否存在于正则表达式相匹配的结果,如果有匹配内容,返回ture,如果没有匹配内容返回false。 【拓展】 match()方法去匹配字符串,如果匹配成功,就返回匹配成功的数组,如果匹配不成功,就返回null; replace()方法去匹配字符串,匹配成功的字符去替换新的字符串。

2、判断字符串是否包含了数字

function contain(str) {
  var reg = /\d/g;
  return reg.test(str);
}
console.log(contain("fds3af"));

3、给定字符串str,检查其是否包含连续重复的字母,包含返回true,否则返回false。

function contain(str) {
   return /([a-zA-Z])\1/.test(str);
}
console.log(contain("fdsaaf"));

【分析】 "小括号包含的表达式所匹配到的字符串" 不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。表达式后边的部分,可以引用前面 "括号内的子匹配已经匹配到的字符串"。引用方法是 "/" 加上一个数字。"/1" 引用第1对括号内匹配到的字符串,"/2" 引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。换句话说,哪一对的左括号 "(" 在前,那这一对就先排序号。

4、判断是否以元音字母结尾。

function contain(str) {
  return /[a,e,i,o,u]$/i.test(str);
}
console.log(contain("fdsaaa"));

5、给定字符串str,检车其是否包含3个连续的数字

function contain(str) {
  return str.match(/\d{3}/g);
}
console.log(contain("1g556777"));

6、判断是否符合指定格式(正确格式示例:556-142-7489)

function contain(str) {
  return /^(\d{3}-){2}\d{4}$/g.test(str);
}
console.log(contain("235-894-5623"));

【解析】 以3个数字加“-”开头,并且重复2次,最后为4个数字。

7、 写一个正则表达式,匹配 "

let str = '<OPTION  value="待处理">待处理</OPTION>';
let regExp = /^<.*?>/g;
console.log(regExp.exec(str)[0]); 

【分析】 以<开头,匹配除了回车符合换行符之外的所有字符,出现任意次,出现零次或一次,这就匹配到了所有的字符。exec()方法返回一个匹配项的数组,而match()方法返回所有匹配项组成的数组。

8、如何获取一个字符串中的数字字符,并按数组形式输出,如: dgfhfgh254bhku289fgdhdy675gfh输出[254,289,675]

let str = 'dgfhfgh254bhku289fgdhdy675gfh';
let regExp = /\d+/g;
console.log(str.match(regExp));

【分析】 +含义是出现一次或多次(至少出现一次)。

9、敏感词过滤

let str = '我草你妈哈哈背景天胡景涛哪肉涯剪短发欲望';
let regExp = /草|肉|欲|胡景涛/g;
let result = str.replace(regExp,"*");
console.log(result);

以上的是缩减版,下面来个完整版的:

let str = '我草你妈哈哈背景天胡景涛哪肉涯剪短发欲望';
let regExp = /草|肉|欲|胡景涛/g;
let result = str.replace(regExp, function (match) {
  let len = match.length;
  let str;
  switch (len) {
    case 1:
      str = '*';
      break;
    case 2:
      str = "**";
      break;
    case 3:
      str = "***";
      break;
    default:
      str = '****';
  }
  return str;
});
console.log(result); //我*你妈哈哈背景天***哪*涯剪短发*望

10、让2013-6-7 变成 2013.6.7

let str = '2013-6-7';
let regExp = /-/g;
console.log(str.replace(regExp, '.')); //2013-6-7

11、给定这样一个连字符串,写一个function转换为驼峰命名法形式的字符串 getElementById

var s1 = "get-element-by-id";
function camelCased(str) {
  let regExp = /-(\w)/g;
  str.replace(regExp, function(match, p) {
      return p.toUpperCase();
   })
}
camelCased(s1);

【分析】 \w代表的是单词字符

12、判断字符串中是否包含数字

let str1 = 'abc9efh';
let str2 = 'abcefg';
let regExp = /\d/;
console.log(regExp.test(str1)); // true
console.log(regExp.test(str2)); // false

13、判断连续重复字母

let str1 = 'abc3d4e5';
let str2 = 'aab2c3';
let regExp = /([a-zA-Z])\1/;
console.log(regExp.test(str1));//false
console.log(regExp.test(str2));//true

14、给定字符串 str,检查其是否包含 3 个连续的数字

15、给定字符串 str,检查其是否符合美元书写格式

16、对人口数字的格式化处理,三位数字用一个','(逗号)隔开

function numberWithCommas(x) {
    //对右侧人口数字的格式化处理,三位数字用一个','(逗号)隔开
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
console.log(numberWithCommas(12345678))//12,345,678

【分析】 非单词边界,匹配右边有三个数字符的数(正向前瞻),匹配一次或者多次;匹配负向前瞻。

17、将单词is替换为IS

let str = 'English poetry is one of their great heritages';
console.log(str.replace(/\bis\b/,'IS'));
// English poetry IS one of their great heritages

18、实现数字转千分位

var reg = /\d{1,3}(?=(\d{3})+$)/g;
var str = "1234556789";
console.log(str.replace(reg,"$&,"));

【分析】 数字千分位的特点是:第一个逗号后面数字的个数是3的倍数,正则:/(\d{3})+$/;第一个逗号前最多可以有1至3个数字,正则:/\d{1,3}/。加起来就是/\d{1,3}(\d{3})+$/,?=含义是零宽度正预测先行断言,具体用法自行百度^_^ 【其他】

var reg = /\d{1,3}(?=(\d{3})+$)/g;
var str = 1234556789;
console.log(str.toString().replace(reg,"$&,"));

19、校验身份证的正确性 完全照搬网上的大佬代码,具体详情戳这里,下面看实现代码

export function idCard(idcode) {
  // 加权因子
  var weight_factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  // 校验码
  var check_code = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
  var code = idcode + "";
  //最后一个
  var last = idcode[17];
  var seventeen = code.substring(0, 17);
  // 判断最后一位校验码是否正确
  var arr = seventeen.split("");
  var len = arr.length;
  var num = 0;
  for (var i = 0; i < len; i++) {
    num = num + arr[i] * weight_factor[i];
  }
  // 获取余数
  var resisue = num % 11;
  var last_no = check_code[resisue];
  var idcard_patter = /^[1-9][0-9]{5}([1][9][0-9]{2}|[2][0][0|1][0-9])([0][1-9]|[1][0|1|2])([0][1-9]|[1|2][0-9]|[3][0|1])[0-9]{3}([0-9]|[X])$/;
  // 判断格式是否正确
  var format = idcard_patter.test(idcode);
  // 返回验证结果,校验码和格式同时正确才算是合法的身份证号码
  return last === last_no && format ? true : false;
}

十、参考文章

由于正则表达式真的是难以灵活运用和讲清楚,因为它实在是太强大了,只有不断的训练自己,多看并多练才有可能完全掌握它,下面提供一些参考文章。

面试系列:关于正则表达式 正则表达式面试题 一些正则表达式的随记 正则表达式总结1 从面试到正则 正则表达式总结2