场景与实训 - 每周每月练习

  • 作者:KK

  • 发表日期:2019.08.31


前言

对于新手程序员来说,正则总是他们偶尔要用到又不怎么熟悉的部分,不容易自己写出一个匹配规则,要看一些基础资料才可以,在此我希望这篇文章里的一些练习过程能帮助大家快速熟悉正则。这个练习建议大家每月甚至每周都尽量练习一遍,练上十多遍就可以了。


练习工具:浏览器控制台

不过你是不是 Web 开发者,用浏览器控制台来调试练习是一个很便捷的方式哦,打开 Chrome 内核的浏览器,按 F12 弹出开发者工具,切换到 Console 面板。

输入/c\d+q/.test('abc123ddx')回车,结果是 false 表示匹配失败,因为它要求字母 c 后面跟一串数字再后面跟个字母 q ,我们改成/c\d+d/.test('abc123ddx')结果就为 true 了。


为了方便重复执行代码,以下变量使用了var声明而不是let声明。

练习1:+ 号基础、英数字匹配、回避干扰内容

  1. 提取句子里面的数字

    var str = '小明今年13岁了';
    var matchResult = str.match(/\d+/);
    console.log('匹配结果的数量', matchResult.length);
    console.log('岁数是', matchResult[0]); //13
    console.log('判断是否匹配', /\d+/.test(str)); //true
    
    var str = '小明今年13岁了';
    var matchResult = str.match(/\d/);
    console.log('匹配结果的数量', matchResult.length);
    console.log('岁数是', matchResult[0]); //1  之所以不是13,是因为 \d 虽然代表数字,但只匹配1次,所以只匹配了第1个数字,用  \d+ 表示1个或多个连续的数字才能像开头那样匹配出13
    
    var str = '小明今年13岁了,在上6年级';
    var matchResult = str.match(/\d+/);
    console.log('匹配结果的数量', matchResult.length); //1
    console.log('岁数是', matchResult[0]); //13
    console.log('年级是', matchResult[1]); //undefined  这里匹配不到后面的 6 是因为只匹配了一次就停止了,要换成全局匹配模式,往下看全局模式
    

    表达式里的\d表示数字,后面的+号表示前者的一个或多个,也就是一个或多个数字。

  2. 全局模式

    var str = '小明今年13岁了,在上6年级';
    var matchResult = str.match(/\d+/g); //js只要在表达式后面加个g就可以,php要从preg_match函数换成preg_match_all函数,python要将serch或match换成findall函数,Java更加复杂,各种语言的全局匹配方式都不同
    console.log('匹配结果的数量', matchResult.length); //2
    console.log('岁数是', matchResult[0]); //13
    console.log('年级是', matchResult[1]); //6
    
  3. 提取一句话里面的英数字

    var str = '小明的英文名是Jay';
    var matchResult = str.match(/\w+/);
    console.log('提取到的英文名是', matchResult[0]); //Jay
    
    var str = '我的微信账号是kk5201314,你加我吧';
    var matchResult = str.match(/\w+/);
    console.log('微信号是', matchResult[0]); //kk5201314
    
  4. 避开干扰的内容,提取你需要的内容

    var str = 'Hi! Marie,我的微信账号是kk5201314,你加我吧!';
    var matchResult = str.match(/\w+/);
    console.log('结果不是个账号', matchResult[0]); //Hi
    var matchResult = str.match(/账号是\w+/);
    console.log('加上中文就好了', matchResult[0]); //账号是kk5201314   可是前面有中文
    var matchResult = str.match(/账号是(\w+)/);
    console.log('只有账号了', matchResult[1]); //kk5201314   表达式里加括号说明它是你需要的,括号里表达式的匹配结果会追加在数组的后面,从下标1开始往后排
    

    表达式里的\w表示英文数字组合。


练习2:区间和枚举匹配

这里用到的知识点叫区间,用方括号括住,表示“某几个元素”

  1. 匹配指定的数字

    var str = '小明17岁';
    console.log('判断里面是否有7或3', /[73]/.test(str)); //true
    console.log('判断里面是否有2或3或5', /[235]/.test(str)); //false
    console.log('判断里面是否有1到5之间的数字', /[1-5]/.test(str)); //true
    console.log('判断里面是否有0到9之间的数字', /[0-9]/.test('出租屋房号是263')); //true  0到9其实覆盖了所有数字了,因此跟 \d 是一样的
    console.log('判断里面是否有0到8之间的数字', /[0-8]/.test('出租屋房号是999')); //false
    
  2. 匹配指定的英文字母

    var str = '我叫May';
    console.log('判断里面是否有x或y', /[xy]/.test(str)); //true
    console.log('判断里面是否有b或c或q', /[bcq]/.test(str)); //false
    console.log('判断里面是否有a到d之间的字母(就是abcd)', /[a-d]/.test(str)); //true
    console.log('判断里面是否有a到z之间的字母', /[a-z]/.test(str)); //true  覆盖了所有字母了
    console.log('判断里面是否有m或A或Y', /[mAY]/.test(str)); //false  因为是要匹配大小写的
    console.log('判断里面是否有M或y', /[My]/.test(str)); //true
    console.log('判断里面是否有任何英文字母', /[a-zA-Z]/.test(str)); //true 大小写都涵盖
    
  3. 匹配英数字下划线

    var str = '我的账号是 Marie_223';
    console.log('比如用于账号匹配', /[a-zA-Z0-9_]/.test('_')); //true
    console.log('比如用于账号匹配', /[a-zA-Z0-9_]/.test('marie')); //true
    console.log('比如用于账号匹配', /[a-zA-Z0-9_]/.test('443')); //true
    console.log('比如用于账号匹配', /[a-zA-Z0-9_]/.test('!')); //false
    
    console.log('比如用于账号匹配', /\w/.test('_')); //true
    console.log('比如用于账号匹配', /\w/.test('marie')); //true
    console.log('比如用于账号匹配', /\w/.test('443')); //true
    console.log('比如用于账号匹配', /\w/.test('!')); //false
    
  4. 匹配某些词组

    var str = '我叫May';
    console.log(/(中国|美国)/.test('我是中国人')); //true
    console.log(/(中国|美国|德国)/.test('我是美国人')); //true
    console.log(/(中国|美国)/.test('我是法国人')); //false
    

练习3:连续次数

  • 匹配连续3个字母a

    var str = '昵称是aaa';
    console.log(/a{3}/.test(str)); //true
    console.log(/a{2}/.test(str)); //true 连续2个也满足
    console.log(/a{4}/.test(str)); //false 4个就没有了
    

    没错,次数就是用花括号包住的

  • 匹配连续2到3个字母a

    console.log(/a{2,3}/.test('昵称是aa')); //true
    console.log(/a{2,3}/.test('昵称是aaa')); //true
    console.log(/a{2,3}/.test('昵称是axa')); //false
    

    花括号里用逗号隔开两个数字,左边是最小匹配数目,右边是最大匹配数目

  • 匹配最多或最小的连续次数

    注意下面用了全局模式来匹配所有可能符合的内容

    //匹配2个或2个以上的连续字母 b ,也就是最少2个起
    var str = '我的昵称是bbb,我有一台bb机,但我不是个傻b';
    console.log(str.match(/b{2,}/g)); //bb 和 bbb ,但后面的单个b达不到连续2个以上就没匹配它了
    
    //匹配最最多2个连续大写字母 I
    var str = '某国家的股票代码是 II{数字} 的格式,最少会有1个字母I,比如 II4572或I3143';
    console.log(str.match(/I{,2}\d+/g)); //II4572 和 I ,但后面的单个b达不到连续2个以上就没匹配它了
    
    var str = 'abcd';
    console.log(/c{1,}/.test(str)); //true   至少有1个c没错
    console.log(/h{0,}/.test(str)); //true   因为最小要求是0个,所以没有h也符合
    

练习4:任意字符

.这个点号在正则里是“任意字符”的意思,类似其SQL里的*号(通配符)

console.log(/a/.test('bat'), '看看有没有字母a,当然有'); //true
console.log(/a/.test('bt'), '看看有没有字母a,当然没有'); //false

console.log(/./.test('bt'), '看看有没有任意字符,那只要不是空就有'); //true
console.log(/./.test('')); //false

console.log(/b.t/.test('bat'), 'b 任意字母 再加个 t'); //true
console.log(/b.t/.test('bt'), 'b 和 t 没有任何字符,不满足'); //false
console.log(/bt/.test('bat')); //false

console.log(/b.{3}t/.test('babct'), '中间3个任意字符'); //true
console.log(/b.{2,3}t/.test('bact'), '中间2~3个任意字符'); //true
console.log(/b.{2,3}t/.test('bacxt'), '中间2~3个任意字符'); //true
console.log(/b.{2,3}t/.test('bacx99t'), '预期只要2~3个,实际上b和t之间却有5个'); //false

练习5:次数简写

  • 匹配1次或多次

    var str = 'abc7d';
    //是否存在1个数字
    console.log(/\d/.test(str)); //true
    console.log(/\d{1}/.test(str)); //true
    console.log(/\d{1,}/.test(str)); //true
    console.log(/\d+/.test(str)); //true    注意这里的 + 号
    console.log(/\d+/.test('abcd')); //false
    

    +号的意思就是:匹配前面定义的那个内容1次或多次,其实跟{1,}是等效的,是一个简写形式。

    下面匹配HTML里的图片地址试试:

    console.log('<img src="http://xxx.com/123.jpg">'.match(/src="(.+)"/)); //匹配成功
    console.log('<img src="">'.match(/src="(.+)"/)); //null
    
  • 匹配0次或多次

    其实就是*号,它跟{0,}是等效的。

    console.log('<img src="http://xxx.com/123.jpg">'.match(/src="(.*)"/)); //匹配成功
    console.log('<img src="">'.match(/src="(.*)"/)); //也成功
    
    //身份证号匹配测试
    console.log(/\d{17}X*/.test('44281319990909343X'), '0个或多个X'); //true
    console.log(/\d{17}X*/.test('44281319990909343'), '0个或多个X'); //true
    console.log(/\d{17}X*/.test('4428131999090934'), '数字的字数不足'); //false
    	
    //0个或多个空格,0个或多个分号
    console.log('nickname = "小白兔";'.match(/nickname *= *"(.+)";*/)); //匹配成功
    console.log('nickname     =      "小白兔";'.match(/nickname *= *"(.+)";*/)); //匹配成功
    console.log('nickname="小白兔"'.match(/nickname *= *"(.+)";*/)); //匹配成功
    

练习6:行首、行尾、多行匹配

  1. 判断是否指定内容开头

    在表达式前面加^说明开始必须是某些内容

    console.log(/^abc/.test('abcde')); //true
    console.log(/^bbc/.test('abcde')); //false
    
    console.log(/^\d+/.test('123开始!')); //true
    console.log(/^[a-zA-Z]+/.test('123开始!')); //false
    
  2. 判断是否以指定内容结尾

    在表达式后面加$

    console.log(/中国人$/.test('我是中国人')); //true
    console.log(/中国人$/.test('我是中国人!')); //false  多了个叹号
    console.log(/中国人$/.test('我是美国人')); //false
    
    console.log(/\d+$/.test('我家话是12334567')); //true
    console.log(/[a-zA-Z]+$/.test('我家话是12334567')); //true
    

练习7:不要指定内容

  1. 匹配 Windows 后面不带 2000 的单词

    console.log(/Windows(?!2000)/.test('Windows2000')); //false
    console.log(/Windows(?!2000)/.test('Windows2008')); //true
    console.log(/Windows(?!2000|2008)/.test('Windows2008'), '后面带2000和2008都不要,内部用 | 隔开'); //false
    
  2. 不匹配 Windows 后面带数字 的单词

    其实表达“不匹配某些内容”还可以在区间方括号([ ])里面以^开头表示这里的内容是不参与匹配的

    console.log(/Windows(?!\d+)/.test('Windows2000')); //false
    console.log(/Windows[^\d]+/.test('Windows2000')); //false
    console.log(/Windows[^0-9]+/.test('Windows2000')); //false
    
    console.log(/Windows(?!\d+)/.test('WindowsXP')); //true
    console.log(/Windows[^\d]+/.test('WindowsXP')); //true
    console.log(/Windows[^0-9]+/.test('WindowsXP')); //true
    

练习8:空白、单词边界

  1. 匹配空格

    \s

    console.log('<img src="http://xxx.com/123.jpg">'.match(/<img\s+src="(.+)"/));
    
    //加多几个空格也一样
    console.log('<img      src="http://xxx.com/123.jpg">'.match(/<img\s+src="(.+)"/));
    
  2. 匹配tab符

    其实\s代表了空白,包括了空格tab,注意鼠标拖选下面 img 后面的空白,能发现它是 tab 符,不是空格哦

    console.log('<img			src="http://xxx.com/123.jpg">'.match(/<img\s+src="(.+)"/));