举一反三,通过练习题学习正则表达式

187 阅读1分钟

对于正则表达式,相信大家跟我一样都是看完基础知识就觉得自己会了,但一放到实际问题上发现又全都忘了。归根结底就是没有融会贯通,只掌握了理论知识而没有通过大量的实践,忘就是必然。所以我总结了一套正则的练习题,通过做题也就是实践来和理论相结合,达到举一反三的目的。以下问题为本人整理,也算是比较高频的正则问题,大家可以先试着写一下然后对比答案有无出入。若有问题请在评论区交流,有其他的正则题目也欢迎补充

  1. 两边空格数不确定,中间字符串内部可能会有空格,通过正则匹配出中间的字符串(带空格) " a b c "

    答案

    /^\s*(.+?)\s*$/

    开头的^\s*和结尾的\s*$匹配的是0或者多个空格。 (.+?) 捕获组匹配的是至少一个不为换行符的字符并通过非贪婪模式去匹配,如果不加?则默认为贪婪模式,会将后面的空格也匹配上,这不是我们想要的

  2. 匹配url的查询字符串并提取参数值

    "https://github.com/README-cn.md?id=12332&name=abc&ui=lanhu"

    输入id, 返回123 输入name, 返回abc 输入ui, 返回lanhu

    答案
    function getValue(str, key){
        const reg = new RegExp(`(\\?|&)${key}=([^&]*)(&|$)`, 'i');
        const res = str.match(reg);
        if(res) return res[2];
        return null;
    }
    getValue(url, 'id');
    

    (\\?|&)匹配问号或者&号,([^&]*)匹配非&符号的字符串,(&|$)匹配&或者结尾,最后取捕获组的第2个,也就是([^&]*)

  3. 匹配所有5个字母组成的单词

    This is somthing about regex.

    答案
    /\b\w{5}\b/
    
    • \b匹配的是单词的边界
    • \w{5}匹配有5个字母的单词
    • \w匹配字母数字和下划线,相当于[a-zA-Z0-9_]
  4. 匹配所有所有手机号

    These are some phone numbers 915-134-3122. Also,
    you can call me at 643.123.1333 and of course,
    I'm always reachable at (212)867-5509
    

    需要取到 915-134-3122, 643.123.1333(212)867-5509

    答案
    \(?\d{3}[-.)]\d{3}[-.]\d{4}
    

    \(?匹配开头可能有的括号 \d{3}匹配3位数字 [-.)]匹配可能出现的-.)符号 PS: []中的特殊字符不需要转义,就表达特殊字符本身的字面意思

  5. 分割提前句子中的单词

    var s = "unicorns and rainbows. And, Cupcakes";
    

    取出句子中所有的单词为数组。

    答案
    s.split(/[\s.,]+/)
    
    

    \s匹配空格,如果通过‘或’匹配.,需要加[]+匹配至少一个,因为空格或者符号可能有多个。

  6. 匹配markdown链接的链接文字和链接地址

    [google](http://google.com)
    [itp](http://itp.nyu.edu)
    [Coding Rainbow](http://codingrainbow.com)
    

    匹配markdown链接的链接文字和链接地址

    答案
    \[(.+?)\]\((http.+?)\)
    

    \[(.+?)\]通过转义符匹配[],(.+?)捕获组匹配任意至少一个字符并设置为非贪婪匹配防止匹配这种情况: [google](http://google.com), [test]

    \((http.+?)\)通过转义符匹配(),(http.+?)捕获组匹配http开头的文本内容,并设置非贪婪模式防止匹配到冗余信息

  7. 转化为驼峰命名

    
    var s1 = "get-element-by-id"; 
    
    

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

    答案
    function toCamelCase(str){
        return s.replace(/-\w/g, function(x){
            return x.slice(1).toUpperCase();
        })
    }
    

    /-\w/g 匹配-e, -b, -i

  8. 通过正则过滤HTML标签

    
    var str="<p id='root-me'>dasdsa</p>nice <br> test</br>"
    
    

    匹配文本中的html标签,并将其过滤掉

    答案
    function filterHtml(str){
        const re = /<[^<>]+>/g;
        return str.replace(re, ' ');
    }
    

    <[^<>]+>匹配的是html标签里面的内容,但内容是除了<>这两个字符以外的所有内容。

  9. URL截取

    
    const url = 'http://www.ngaiwe.com/page/index.html?name=weiran&age=27&sex=0#develpoment'
    
    

    我们想要的是参数转化键值对和哈希值{name: 'weiran',age: 27, sex: 0, HASH: 'develpoment'}

    答案
    function urlParamToObject(url){
        const obj = {}
        str.replace(/([^?=&#]+)=([^?=&#]+)/g, function(x, y, z){
            obj[y] = z;
        })
    
        str.replace(/#([^?=&#]+)/, function(x, y){
            obj['hash'] = y;
        })
        return obj;
    }
    
    

    replace第二个回调的参数分别是匹配的子串、和匹配的捕获组(第n个括号匹配的字符串)

  10. 匹配xxyy模式

    可能匹配aabb诸如此类。

    答案

    /(\w)\1(\w)\2/

    \n意思匹配第n个捕获组的相同内容。

  11. 字符串的缩短

    aaaaabbbbbccc,中间不知道有多少重复内容,使用正则表达式变成abc

    答案
    const a = `aaaaabbbbbccc`;
    a.replace(/(\w)\1*/g, '$1')
    
    

$n的意思是保存的第n个捕获组里面的内容,上面就是(\w)即匹配的字母, 或者叫做反向引用

  1. 更改日期格式

    2017-03-12更改为03/12/2017的格式

    答案
    const reg = /(\d{4})-(\d{2})-(\d{2})/;
    
    const date = '2017-03-12';
    
    const res = date.replace(reg, '$2/$3/$1')
    
    //或者是
    
    const res = date.replace(reg, (match, y, m, d)=>`${m}/${d}/${y}`)