• 第10章 正则表达式


    1. 为什么需要正则表达式

    • 正则表达式可以用来:
      • 操作HTML节点中的字符串
      • 使用CSS选择器表达式定位部分选择器
      • 判断一个元素是否具有指定的类名(class)
      • 输入校验
      • 其他任务

    2. 正则表达式进阶

    2.1 正则表达式说明

    创建正则表达式

    // 字面量创建
    const pattern = /test/ig;
    // 实例化正则对象
    const pattern = new RegExp("test", "ig");
    

    当正则表达式再开发环境是明确的,推荐有限使用字面量语法;当需要再运行时动态创建字符串来构建正则表达式时,则使用构造函数的方式

    5个修饰符

    修饰符 作用
    i ignore,忽略大小写
    g global,查找所有匹配项
    m multiple,允许多行匹配,对获取textarea元素的值很有用
    y 开启粘连匹配。正则表达式执行粘连匹配时试图从最后一个匹配的位置开始
    u 允许使用Unicode点转义字符(u{...})

    2.2 术语和操作符

    名称 示例 示例含义
    精确匹配 /test/ 4个字母必须完全出现在所匹配的字符串中
    匹配字符集 [abc] 匹配a、b、c中的任意一个字符
    [^abc] 匹配除了a、b、c的任意字符
    [a-z] 匹配从a到z所有小写字母
    转义 [] 让程序将[]识别为字符,而不是操作符
    起止符号 /^test/ 匹配以test开头的字符串
    /test$/ 匹配以test结束的字符串
    重复出现 /t?est/ 同时匹配est和test
    在字符后面加?表示这个字符可以出现0次或1次
    /t+est/ 匹配test、ttest、tttest等
    在字符后面加+表示这个字符可以出现1次或多次
    /t*est/ 匹配est、test、ttest、tttest等
    在字符后面加*表示这个字符可以出现0次或1次或多次
    /a{4}/ 匹配4个连续的字符a
    用大括号指定重复次数
    /a{2,4} 匹配2~4个连续的字符a
    /a{2,} 匹配2个或更多个连续的字符a
    分组 /(ab)+ 匹配一个或多个连续的ab
    括号扩起表示一个整体,共享后面的操作符
    或(or) /a|b/ 匹配字符a或者字符b
    反向引用 /^([dtn])a1/ 匹配以字符d、t或n开头,其后连接字符a,
    再后连接一个第一个分组(也就是括号中)中捕获的内容
    1匹配的具体字母要在运行时才能确定
    引用正则中定义的捕获,第一个分组的捕获为1,第二个为2
    反向引用在匹配XML类型的标记元素时很有用,如/<(w+)>(.+)</1>/

    表示重复出现的运算符默认是贪婪模式,可以匹配所有可能的字符。在运算符后添加?使运算符为非贪婪模式,只进行最小限度的匹配。如对于字符串aaa,/a+/会匹配aaa,/a+?/则会匹配a、a、a。

    预定义元字符 匹配的字符集
    水平制表符
     空格
    v 垂直制表符
    f 换页符
    回车符
    换行符
    cA:cZ 控制字符
    u0000:uFFFF 十六进制Unicode码
    x00:xFF 十六进制ASCII码
    . 匹配除换行字符( 、 、u2028和u2029)之外的任意字符
    d 匹配任意十进制数字,等价于[0-9]
    D 匹配除了十进制数字的任意字符,等价于[^0-9]
    w 匹配任何字母、数字和下划线,等价于[A-Za-z0-9_]
    W 匹配除了字母、数字和下划线的任意字符,等价于[^A-Za-z0-9_]
    s 匹配任意空白字符(包括空格、制表符、换页符等)
    S 匹配除了空白字符的任意字符
     匹配单词边界
    B 匹配非单词边界(单词内部)

    3. 编译正则表达式

    3.1 创建正则表达式的两种方法

    // 字面量创建
    const re1 = /test/i;
    // 实例化正则对象
    const re2 = new RegExp("test", "i");
    
    console.log(re1.toString() === "/test/i");
    // true
    
    // 用test方法检验字符串
    console.log(re1.test("Test"));
    // true
    console.log(re2.test("tesi"));
    // false
    
    // 每个正则对象都是独一无二的
    console.log(re1.toString() === re2.toString());
    // true
    console.log(re1 === re2);
    // false
    

    3.2 在运行时编译一个供稍后使用的正则表达式

    <div id="wango" class="human student son brother"></div>
    <span></span>
    <div id="lily" class="human student daughter sister"></div>
    <div id="jack" class="human teacher son father"></div>
    <script>
        function findClassInElements(className, type) {
            // getElementsByTagName方法返回的不是数组,是 HTMLCollection(HTML集合)
            // 在WebKit内核的浏览器中返回一个 NodeList,所以不能使用数组方法
            const elems = document.getElementsByTagName(type || "*");
    
            // 类名的规则:直接开头或者以空格开头,直接结束或者以空格结束
            // 当创建正则表达式字面量时,只需使用一个反斜线(s)
            // 但这里是在字符串中写反斜线,就必须使用双反斜线(\s)进行转义
            const reg = new RegExp("(^|\s)" + className + "(\s|$)");
            const results = [];
            // 在for循环中先将长度储存,避免每次循环都去访问对象再返回长度,
            // 以优化性能(长度不能是动态的)
            for (let i = 0, len = elems.length; i < len; i++) {
                if (reg.test(elems[i].className)) {
                    results.push(elems[i]);
                }
            }
            return results;
        }
    
        findClassInElements("student", "div").forEach(elem => {
            console.log(elem.id);
        });
        // wango
        // lily
    
        findClassInElements("son").forEach(elem => {
            console.log(elem.id);
        });
        // wango
        // jack
    </script>
    

    4. 捕获匹配的片段

    4.1 执行简单捕获

    <div id="square" style="transform: translateY(15px);background-color: black;"></div>
    <script>
        function getTransformY(elem) {
            const transformValue = elem.style.transform;
            if (transformValue) {
                // 用括号分组,使用match方法(由字符串调用)捕获匹配的值,返回数组
                const match = transformValue.match(/^translateY(([^)]+))$/);
                // const match = transformValue.match(/^translateY((.+))$/);
                // match方法匹配结果通过第一个索引返回,然后每次捕获结果索引递增
                return match ? match[1] : "";
            }
            return "";
        }
    
        const square = document.getElementById("square");
        console.log(getTransformY(square));
        // 15px
    </script>
    

    4.2 使用全局表达式进行匹配

    const html = '<div class="test"><b>hello</b><i>world!</i></div>';
    
    // 使用局部正则表达式可以返回数组,
    // 数组包含第一个匹配的全部内容以及操作中的全部捕获结果
    const results = html.match(/<(/?)(w+)([^>]*?)>/);
    console.log(results[0]);    // <div class="test">
    console.log(results[1]);    // 
    console.log(results[2]);    // div
    console.log(results[3]);    // class="test"
    
    // 使用全局正则表达式可以返回数组
    // 数组包含全部匹配结果,但不返回捕获内容
    const all = html.match(/<(/?)(w+)([^>]*?)>/g);
    console.log(all[0]);        // <div class="test">
    console.log(all[1]);        // <b>
    console.log(all[2]);        // </b>
    console.log(all[3]);        // <i>
    console.log(all[4]);        // </i>
    console.log(all[5]);        // </div>
    
    let match;
    const rslts = [];
    const reg = /<(/?)(w+)([^>]*?)>/g;
    // 使用exec方法(正则调用)进行捕获和全局搜索
    // 每次调用都可以返回下一个匹配的结果,
    // 结果包含第一个匹配的全部内容以及操作中的全部捕获
    while ((match = reg.exec(html)) !== null) {
        rslts.push(match);
    }
    
    console.log(rslts[0][0]);   // <div class="test">
    console.log(rslts[0][1]);    // 
    console.log(rslts[0][2]);    // div
    console.log(rslts[0][3]);    // class="test"
    

    4.3 捕获的引用

    <b class="hello">Hello</b><i>world!</i>
    <script>
        const html = '<b class="hello">Hello</b><i>world!</i>';
        // 使用1指向正则表达式中的第1个捕获
        const reg = /<(w+)([^>]*)>(.*?)</1>/g    // 仅作示例,并不完美
        let match = reg.exec(html);
    
        console.log(match[0]);  // <b class="hello">Hello</b>
        console.log(match[1]);  // b
        console.log(match[2]);  //  class="hello"
        console.log(match[3]);  // Hello
    </script>
    

    4.4 未捕获的分组

    // 用作分组的括号也会被识别为捕获内容
    const reg1 = /((hello-)+)world/;
    let match = "hello-hello-world".match(reg1);
    console.log(match[0]);  // hello-hello-world
    console.log(match[1]);  // hello-hello-
    console.log(match[2]);  // hello-
    
    // 在起始圆括号之后使用?:创建被动子表达式,使不被捕获
    const reg2 = /((?:hello-)+)world/;
    match = "hello-hello-world".match(reg2);
    console.log(match[0]);  // hello-hello-world
    console.log(match[1]);  // hello-hello-
    console.log(match[2]);  // undefined
    

    5. 利用函数进行替换(replace方法)

    // 基本用法
    console.log("ABCDEfg".replace(/[A-Z]/g, "X"));
    // XXXXXfg
    
    // replace方法第二个参数可以是函数,
    // 这时,对每一个匹配到的值都会调用一次这个函数,
    // 从函数返回的值作为匹配字符串的替换值
    
    // 将下划线连接的字符串转换为小驼峰字符串
    // 第二个参数函数接收多个参数,第一个是匹配的字符串,之后的参数是捕获结果
    console.log("this_is_an_array".replace(/_(w)/g, (all, letter) => letter.toUpperCase()));
    // thisIsAnArray
    
    // 一种查询字符串压缩技术
    function compress(str) {
        const keys = {};    // 存储键值对
        // 提取键值对信息
        str.replace(/([^=&]+)=([^&]*)/g, (all, key, value) => {
            keys[key] = (keys[key] ? keys[key] + "," : "") + value;
            return "";  
            // 只是利用replace的查找和调用函数功能,
            // 不在意执行结果,所以可以返回任意值
        });
        // 收集key信息
        const result = [];
        for (let key in keys) {
            result.push(key + "=" + keys[key]);
        }
        return result.join("&");
    }
    
    const str = "foo=1&foo=2&blah=a&blah=b&foo=3";
    console.log(compress(str));
    // foo=1,2,3&blah=a,b
    

    6. 使用正则表达式解决常见的问题

    6.1 匹配换行

    const html = "<b>Hello</b>
    <i>world!</i>";
    console.log(/.*/.exec(html)[0]);    // 不匹配换行符
    // <b>Hello</b>
    console.log(/[Ss]*/.exec(html)[0]);   // 匹配全部字符(最优解)
    // <b>Hello</b>
    // <i>world!</i>
    console.log(/(?:.|s)*/.exec(html)[0]); // 匹配换行符
    // <b>Hello</b>
    // <i>world!</i>
    

    6.2 匹配Unicode字符

    const text = "u6211u7231u4f60uff0cu4e2du56fduff01";
    const mathchAll = /[wu0080-uFFFF_-]+/; // 匹配所有字符,包括Unicode
    console.log(text.match(mathchAll)[0]);
    // 我爱你,中国!
    

    6.3 匹配转义字符

    // 允许任意字符序列组成的词,包括一个反斜线紧跟
    // 任意字符(包括反斜线本身),或兼而有之
    const pattern = /^((w+)|(\.))+$/;
    
    // 测试字符串,除了最后一个,其他均通过
    const tests = [
        "formUpdate",
        "form\.update\.whatever",
        "form\:update",
        "\f\o\r\m\u\p\d\a\t\e",
        "form:update"
    ];
    
    let flag = true;
    for (let i = 0, len = tests.length; i < len; i++) {
        if (!pattern.test(tests[i])) {
            flag = false;
            console.log(tests[i], "is invalid!");
        };
    }
    console.log(flag);
    // form:update is invalid!
    // false
    
  • 相关阅读:
    Dynamic attention in tensorflow
    Dynamic seq2seq in tensorflow
    Tensorflow Seq2seq attention decode解析
    zz图像卷积与滤波的一些知识点
    Android SDK更新失败对策
    高维数据降维 国家自然科学基金项目 2009-2013 NSFC Dimensionality Reduction
    近期深度学习论文汇总
    PHP远程连接mysql报错处理办法
    zz 启动Matlab提示Microsoft Visual C++ 2005 Redistributable存在问题问题
    `fw服务端非完整` 工程开发初期的工作
  • 原文地址:https://www.cnblogs.com/hycstar/p/14050413.html
Copyright © 2020-2023  润新知