乐趣区

通过实例学习正则表达式

判断邮箱是否正确

邮箱正则

/\w+[\w\.]*@[\w\.]+\.\w+/

测试用例

const regex = /\w+[\w\.]*@[\w\.]+\.\w+/

regex.test('666@email.com')            // true
regex.test('july@e.c')                 // true               
regex.test('_@email.com.cn')           // true
regex.test('july_1234@email.com')      // true

regex.test('@email.com')               // false
regex.test('julyemail.com')            // false
regex.test('july.email.com')           // false
regex.test('july@')                    // false
regex.test('july@email')               // false
regex.test('july@email.')              // false
regex.test('july@.')                   // false
regex.test('july@.com')                // false
regex.test('-~!#$%@email.com')         // false

正则讲解

  1. \w。 \w 属于一种 预定义模式,表示匹配任意的字母、数字和下划线。点击查看其他预定义模式。
  2. +、*。 +、* 和?在正则表达式中被称为 量词符。+ 表示一次或多次,* 表示 0 次或多次,?表示 0 次或一次。
  3. \.。 . 在正则表达式中被称为 元字符,它可以匹配除回车(\r)、换行(\n)、行分隔符(\u2028)和段分隔符(\u2029)以外的所有字符。因为元字符有特殊含义,所以如果要匹配元字符本身,就需要使用转义字符,也就是在前面加上反斜杠 (\)。点击查看其他元字符
  4. [\w\.]。 [] 表示一个 字符集合,比如 [july] 不是表示匹配整个单词,而是表示 j、u、l 和 y 组成的一个字符集合,匹配时只要匹配到其中一个字母就表示匹配成功。点击查看字符集合详解
  5. 总览

匹配 URL 地址

URL 正则

/https?:\/\/(\w*:\w*@)?[-\w\.]+(:\d+)?(\/([\w\/\.]*(\?\S+)?)?)?/

测试用例

const regex = /https?:\/\/(\w*:\w*@)?[-\w\.]+(:\d+)?(\/([\w\/\.]*(\?\S+)?)?)?/

regex.test('http://www.forta.com/blog')                    // true
regex.test('https://www.forta.com:80/blog/index.cfm')      // true
regex.test('https://www.forta.com')                        // true
regex.test('http://ben:password@www.forta.com/')           // true
regex.test('http://localhost/index.php?ab=1&c=2')          // true
regex.test('http://localhost:8500/')                       // true

正则讲解

  1. ()。类似于 (\w:\w*@) 这样的表达式被称为 子表达式 ,相比于字符集合[] 匹配时只匹配集合中的一个字符,子表达式是将括号内的表达式作为一个整体来匹配。比如 ( :\d+)匹配类似于“:8080”这样的字符串,而 [:\d] 匹配一个 : 或者一个 数字。
  2. 总览

练习

去掉 html 文件中的所有注释

html 文件

我在本地随便写了一个 html 文件,包含 css、html 和 js3 个部分,是一个完整的网页。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    /* 
      这是 css 的多行注释
      这是 css 的多行注释 这是 css 的多行注释
    */
    * {
      margin: 0;
      padding: 0;
      /* 这是 css 的多行注释 */
    }

    html {color: #000;}
  </style>
</head>

<body>
  <h1>h1 title</h1> <!-- 这是 html 注释 -->

  <h2>h2 title</h2>
  <!--  这是 html 注释 -->
  <button style="/* 这是行内 css 的注释 */color: red/* 这是行内 css 的注释 */">click me</button>
  <button onclick="/* 这是行内 js 的注释 */alert('july')/* 这是行内 js 的注释 */">click me 2</button>
  <!--  
    这是 html 注释 
  -->
  <button onclick="// 这是行内 js 的注释
    alert(/* 注释 */'july')
    // 这是行内 js 的注释 'sdfs' "style='color: blue'>click me 3</button>
  <!--  这是 html 注释 -->

  <script>
    // 这是 js 单行注释
    // 这是 js 单行注释 这是 js 单行注释 
    function func() {console.log('test');  // 这是 js 单行注释
    }

    /*
     * 这是 js 多行注释
     * 这是 js 多行注释 这是 js 多行注释
     */
    function func2() {
      // 这是 js 单行注释
      /*
        这是 js 多行注释
      */
      console.log('test');  /* 
      这是 js 多行注释 */
    } 
  </script>
</body>

</html>

匹配

const htmlStr = `html 字符串 `;   // 将上面的 html 内容拷贝于此,由于太长,就不再拷贝

// 匹配 /* */
htmlStr.match(/\/\*[^]*?\*\//g);  // 该行代码会返回一个数组,长度为 10,数组的每个元素分别对应匹配到的 /* */,由于篇幅有限,就不将结果展示到这里了

// 匹配 <!-- -->
htmlStr.match(/<!--[^]*?-->/g);

// 匹配 //
htmlStr.match(/(\/\/.*?(?=(["']\s*\w+\s*=)|(["']\s*>)))|(\/\/.*)/g);

分析

  1. g 全局修饰符。g 是正则表达式的修饰符,表示全局匹配或者搜索,因为 html 中会有多个注释,所以需要全局修饰符(点击查看全部修饰符)。
  2. [^]。^ 被称为脱字符,我的理解就是取反的意思,比如 [^abc] 表示除了 a、b 和 c,其他所有字符都可以匹配。[^]匹配任意字符,包括换行符。
  3. 非贪婪模式。量词符在默认情况下都是使用贪婪模式进行匹配,比如说上面的[^]* 表示匹配 0 个或多个任意字符,由于是贪婪模式,所以会尽可能多的匹配任意字符,直到不满足条件为止。通过在[^]* 后面加一个?号,就变成了非贪婪模式,这种模式下,一旦条件满足,就不会再往下匹配。想要实际查看两种模式的区别,可以将上方匹配 /* */ 的正则表达式的?去掉再执行,看看返回结果有何不同。
  4. 向前查找 。向前查找就是一个以?= 开头的子表达式。举例说明其意义,比如我们要匹配出 URL 的协议部分,URL:https://www.forta.com,正则:/.+(?=:)/,(?=:) 就是一个向前查找,它表示只要匹配到:,就把:之前的内容返回,: 本身不需要返回。
  5. 前面两种注释的匹配比较容易,第三种也就是 // 这种注释比较复杂。其实对于 // 注释,在绝大多数情况下 /\/\/.*/ 这个正则可以匹配出,但是有两种情况不能满足,见下方代码
<button onclick="alert('july')
    // 这是行内 js 的注释 'sdfs' "style='color: blue'>click me 3</button>
    
<button onclick="alert('july')
    // 这是行内 js 的注释 'sdfs' ">click me 3</button>

我们通过图片详细解析一下

最终代码

为了方便,最终代码选择在 node 环境中执行,因为最初的需求是将 html 中的所有注释去掉,所以我们使用了字符串的 replace 方法,该方法接收两个参数,第一个参数是正则表达式,第二个参数是需要替换成的内容。

const fs = require('fs');

// regex.html 是放在同级目录下的 html 源文件
fs.readFile('./regex.html', 'utf8', (err, data) => {if (err) throw err;

  console.log(
    data
      .replace(/\/\*[^]*?\*\//g, '')    // 替换 /* */
      .replace(/<!--[^]*?-->/g, '')     // 替换 <!-- -->
      .replace(/(\/\/.*?(?=(["']\s*\w+\s*=)|(["']\s*>)))|(\/\/.*)/g, '')  // 替换 // 
  );
});

参考数据或博客

《正则表达式必知必会》
阮一峰 javascript 教程

退出移动版