前端追梦人正则表达式教程

正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。

搜索模式可用于文本搜索和文本替换。

1. 什么是正则表达式?

正则表达式是由一个字符序列形成的搜索模式。

当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。

正则表达式可以是一个简单的字符,或一个更复杂的模式。

正则表达式可用于所有文本搜索和文本替换的操作。

2. 语法

/正则表达式主体/修饰符(可选)

其中修饰符是可选的。

初探正则表达式的魅力

let str = "hello2200world6688";
// 我们要找到字符串str中的数字并拼接成新的字符串
// 不使用正则表达式的话
console.log([...str].filter(a => !Number.isNaN(parseInt(a))).join(""));
// 如果使用正则表达式可以很轻松实现
console.log(str.match(/\d/g).join(""));

3. 正则表达式的创建

  1. 时候用字面量
    例如

    /\d/g
    
  2. 使用构造函数

    let reg = new RegExp("\\d, "g");
    

4. 选择符的使用

console.log(/a|u/);  // 表示监测字符串中a或者u是否存在, 也可以写成这样console.log([au]);表示匹配中括号中其中一个字符
let tel = "010-9999999";
// 下面的检测放阿飞010也为true
console.log(/010|020\-\d{7,8}/.test(tel));
//可以写成这样
console.log(/010\-\d{7,8}|020\-\d{7,8}/.test(tel));
// 更好的是使用原子组,用小括号包围的被视为一组,但是如果是abc010-9999999还是检测为true
console.log(/(010|020)\-\d{7,8}/.test(tel));
// 针对上述问题修改
console.log(/^(010|020)\-\d{7,8}$/.test("abc010-9999999")); // false

5. 字符的转义

// .表示除换行外任意字符 \.则表示普通的.
console.log(/\d+\.\d+/.test(23.34));
// 如果用构造函数的话对\d也需要转义
console.log(new RegExp("\\d+\\.\\d+").test(23.34));
// 如匹配一个网址, 左斜杠需要转义
let url = "https://www.baidu.com";
console.log(/https?:\/\/\w+\.\w+\.\w+/.test(url));

6. 字符的边界约束

使用^表示起始, 使用$表示结束

console.log(/^\d+$/.test("1213"));
console.log(/^[a-z]{3,6}$/.test("abc"));

7. 数值与元字符

\d匹配数值

console.log("helloworld 2020".match(/\d+/g));
console.log("张三:010-9999999,李四:020-8888888".match(/\d{3}-\d{7,8}/g));
// 排除,下面使用^排除掉原子组中的字符,进而取出中文字符
console.log("张三:010-9999999,李四:020-8888888".match(/[^-\d:,]+/g));

\D表示非数值

console.log("123hello".match(/\D+/g));

\s表示空白(包括空格,换行,制表符等)

console.log(/\s/.test(" hello")); // true

\S表示非空白符

console.log(/\S/);

[\s\S]表示任意字符

console.log(/[\s\S]+/.test("hello"));

\w表示字母,数字,下划线

let email = "123456789@qq.com";
console.log(email.match(/^\w+@\w+\.\w+$/));

\W元字符用于查找非单词字符。

单词字符包括:a-z、A-Z、0-9,以及下划线。

console.log("helloworld100%".match(/\W+/g)); // ['%!']

.点元字符表示除换行符外任意字符

console.log("hello123_\n===++".match(/.+/g));

// 使用s单行模式进行匹配,下面使用模板字符串
let str = `
  hello
  helloworld
`;
console.log(str.match(/.+/s)[0]);  
/*
 hello
 helloworld
*/

// 空格是普通字符,可以直接输入也可以使用\s进行匹配
console.log("010 - 8888888").match(/\d+ - \d{8}/);

匹配所有字符

可以使用[\s\S]或者[\d\D]

8. 模式修正符

i不区分大小写

g全局匹配(不使用则匹配到1项即停止)

s单行匹配

m把多行文本的每一行单独处理,

u模式用来处理宽字节字符(4字节)

y模式连续满足条件的匹配(如/\u/y在执行匹配时候需要保证每一次继续匹配需要连续满足条件)

console.log("helloHELLO".match(/he/ig/));

下面是一个使用m模式的实例

let str = `
 #1 js,200元 #
 #2 php,300元 #
 #9 baidu.com # 百度
 # 3 node.js,180元 #
`;
let arr = str.match(/^\s*#\d+\s+.+\s+#$/gm);
console.log(arr);
arr = arr.map(v => {
  v = v.replace(/\s*#\d+\s*/).replace(/\s*#/, "");
  let [name, price] = v.split(",");
  return [name, price];
});
console.log(JSON.stringify(arr, null, 2));

9.字符属性和中文的匹配

字符属性

元字符含义
\p{L}所有字母
\p{N}所有数字,类似于 \d
[\p{N}\p{L}]所有数字和所有字母,类似于 \w
\P{L}不是字母
\P{N}不是数字
\p{P}匹配标点符号
console.log("hello123".match(/\p{L}+/gu)); // hello
// 匹配标点符号
console.log("hello,12!3?").match(/\p{P}+/gu); // [',','!', '?']

使用字符属性Script来根据语言系统查找对应字符

console.log(/\p{sc=Han}/gu);  // 中文

10. lastIndex属性的使用

定义开始检索的位置, 需要使用g模式,否则lastIndex属性一直为0, 需要查看位置信息等属性时候需要使用exec来进行正则匹配

let reg = /\w/g;
while((res = reg.exec("hello world"))){
  console.log(res.lastIndex);
  console.log(res);
}

11.使用y模式

let str = `
 QQ群:11111111, 22222222, 333333333
 欢迎入群, 欢迎入群
`;
let reg = /(\d+),?/y;
reg.lastIndex = 7;
let qq = [];
while((res = reg.exec(str))) qq.push(res[1]);
console.log(qq);

12.原子组的基本使用

let date = '2020-02-23';
let reg = /^\d{4}[-\/]\d{2}[-\/]\d{2}$/;
console.log(reg.test(date););
// 可以使用原子组复用规则
let reg1 = /^\d{4}([-\/]\d{2}\1\d{2})/;   // \1 即复用[-\/]
console.log(reg.test(date));  // 和上述写法等效

区间匹配

console.log(/[0-9]+/g.test("2020"));
console.log(/[a-z]+/g.test("hello"));

排除匹配

let str = "张三:010-88888888,李四:020-99999999";
console.log(str.match(/[^\d:\-,]+/g)); // ['张三', '李四']

原子组字符不解析

let str = "(hello).+";
console.log(str.match(/[(.+)]/gi)); // ( ) . +均被视为普通字符处理 

邮箱验证中原子组的使用

let email = "123456789@163.com.cn";
let reg = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+(\.([a-zA-Z]{2,4}))+$/;
console.log(reg.test(email)); // true

使用原子组完成替换操作

let str = `
	<h1>hello</h1>
  <span>hello</span>
  <h2>hello</h2>
`;
let reg = /<(h[1-6])>([\s\S]*)<\/\1>/gi;
console.log(str.replace(reg, `<p>$2</p>`));
// 我们对于分组在replace第二参数使用函数时候也能够获取到分组内的匹配值
console.log(str.replace(reg, (p0,p1,p2) => `<p>${p2}</p>`);

嵌套分组与不记录分组

let str = `
 https://www.baidu.com
 http://google.com
 https://4399.com
`;
let reg = /https?:\/\/((?:\w+\.)?\w+\.(?:com|org|cn))/gi;  // 原子组内的?:表示该组不被记录分组,即不能通过$1,$2等方式获取到

13.使用正则操纵DOM元素

如删除页面中所有的h1-h6标签

let body = document.body;
let reg = /<(h[1-6])>[\s\S]*<\/\1>/;
body.innerHTML = body.innerHTML.replace(reg, "");

批量正则验证

 <input type="text" name="password" id="password">
    <span id="result"></span>
    <script>
        document.getElementById("password").addEventListener("keyup", function(){
            let reg = [/[\w\-]{5,10}/, /[A-Z].{4,9}/];
            if(reg.every(e => e.test(this.value))){  // every所有元素回调均返回true,结果才为true
                document.getElementById("result").innerHTML = "验证成功";
            } else {
                document.getElementById("result").innerHTML = "验证失败";
            }
        });
    </script>

14. 禁止贪婪

通过在+, *?后添加?来达到禁止贪婪的效果

/str+?/
/str*?/
/str??/

标签替换中的禁止贪婪的使用

  <main>
        <span>hello</span>
        <span>world</span>
        <span>hahaha</span>
    </main>
    <script>
        const main = document.querySelector("main");
        const reg = /<span>([\s\S]*?)<\/span>/gi; // 在*后添加?禁止贪婪,要不然会匹配到main中所有内容
        main.innerHTML = main.innerHTML.replace(reg, (v,p1) => {
            return `<h4 style="color: red;">${p1}</h4>`;
        });
    </script>

15.matchAll

   <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Veniam dolorum minima ipsam at nemo, possimus accusantium consectetur error suscipit harum quidem consequatur repellendus reprehenderit quisquam architecto praesentium voluptate? Soluta, est?</p>
    <h1>hello</h1>
    <h2>world</h2>
    <h3></h3>
    <script>
        let body = document.body;
        let reg = /<(h[1-6])>([\s\S]+?)<\/\1>/gi;
        let it = body.innerHTML.matchAll(reg);
        let contents = [];
        for(const item of it){
            contents.push(item[2]);
        }
        console.table(contents);
    </script>

为低端浏览器定义原型方法match

String.prototype.matchAll = function(){
  let res = this.match(reg);
  if(res){
     let str = this.replace(res[0]).replace(res[0], '^'.repeat(res[0].length));
     let match = str.match(reg) || [];
     return [res, match];
  }
};

let str = `
 <p>hello</p>
 <h1>world</h1>
 <h2>hahaha</h2>
`;
let reg = /<(h[1-6])>([\s\S]+?)<\/\1>/i;
let it = str.matchAll(reg);
let contents = [];
for(const item of it){
  contents.push(item[2]);
}
console.log(contents);

16. 字符串正则方法

方法名用法
test测试字符串是否满足正则规则,返回值为boolean
match配合g模式符进行全局匹配不返回匹配细节,不加g模式客户返回第一个匹配位置的细节
matchALl全局匹配,返回一个迭代器,使用for…of循环可以获取所有匹配项的细节
exec需要配置g模式使用,否则会一直在同一位置进行匹配,使用while循环进行全局匹配时候如果忘记加g模式符会导致死循环, 每次执行exec, reg对象的lastIndex会进行更新

17. $`, $’, $&在字符串替换中的使用(了解)

let str = "=前端梦%";
let reg = /前端梦/;
// $&代表匹配到的内容
console.log(str.replace(reg, "$&")); // =前端梦%
console.log(str.replace(reg, "$`")); // ==%
console.log(str.replace(reg, "$'")); // =%%

**$&**的一个使用实例

<body>
  <main>
  	前端梦,前端梦
  </main>

  <script>
  	const main = document.querySelector("body main");
    main.innerHTML = main.innerHTML.replace(/前端梦/g, "<a href='www.qianduanmeng.com'>$&</a>");
  </script>
</body>

18. 原子组在替换中的小技巧

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <main>
        <a href="http://www.baidu.com">百度</a>
        <a href="http://frontender.com">前端人</a>
        <a href="http://w3c.org">w3c</a>
    </main>

    <script>
        /**
         * 我们要给http后没有s的添加s,没有www的添加www
         * */
        const main = document.querySelector("main");
        const reg = /(<a.*href=['"])(http)(:\/\/)(www\.)?/gi;
        main.innerHTML = main.innerHTML.replace(reg, (...args) => {
            args[2] += 's';
            args[4] = args[4] || "www.";
            console.log(args);
            return args.slice(1,5).join("");
        });
    </script>
</body>
</html>

19. 原子组的别名

可以在原子组内使用?<别名>的方式来为每个原子组定义别名

<body>
    <h1>hello</h1>
    <h2>world</h2>
    <h3>hahaha</h3>

    <script>
        let body = document.body;
        const reg = /<(h[1-6])>(?<con>.*?)<\/\1>/gi;
        body.innerHTML = body.innerHTML.replace(reg, "<h4>$<con></h4>");
    </script>
</body>

使用原子组别名来优化正则

<body>
    <main>
        <a href="https://www.baidu.com">百度</a>
        <a href="https://www.sina.com">新浪</a>
        <a href="http://frontender">前端人</a>
    </main>

    <script>
        const main = document.querySelector("body main");
        const reg = /<a.*?href=(['"])(?<link>.*?)\1>(?<title>.*?)<\/a>/gi;
        const links = [];
        for(const it of main.innerHTML.matchAll(reg)){
            links.push(it.groups);
        }
        console.log(links);
    </script>
</body>

20. ?=先行断言匹配(可以理解为后面是什么的)

<body>
    <main>
        欢迎来到前端人,为大家分享web前端开发常用技术教程
    </main>

    <script>
        let main = document.querySelector("main");
        let reg = /web前端(?=开发)/g;
        main.innerHTML = main.innerHTML.replace(reg, `<a href="www.baidu.com">$&</a>`);
    </script>
</body>

上面的正则表示要匹配后面是开发的web前端字样,断言匹配可以理解为是正则表达式的条件判断

使用先行断言匹配来规范价格

let lessons = `
    js,200元,300次
    php,300.00元,100次
    node.js,180元,260次
`;

let reg = /(\d+)(.00)?(?=元)/gi;
lessons = lessons.replace(reg, (v, ...args) => {
    args[1] = args[1] || '.00';
    return args.splice(0,2).join("");
});

console.log(lessons);

21. ?<=后行断言(可以理解成前面是什么的)

let str = "hello123world456";
let reg = /(?<=hello)\d+/gi; // 匹配前面是hello的数字
console.log(str.match(reg));

结合使用前后行断言批量替换链接地址

<body>
    <a href="https://www.baidu.com">百度</a>
    <a href="https://yahoo.com">雅虎</a>

    <script>
        const body = document.body;
        const reg = /(?<=href=(['"])).+(?=\1)/gi;
        body.innerHTML = body.innerHTML.replace(reg, "https://demo.com");
    </script>
</body>

使用断言模糊电话号码

let users = `
    Tom: 1234567890
    Jack: 9876543210
`;

let reg = /(?<=\d{6})\d{4}/gi;
users = users.replace(reg, v => {
    return "*".repeat(4);
});
console.log(users);

22. ?!负向先行断言(后面不是什么的)

let str = "hello123hdms";
let reg = /[a-z]+(?!\d+)$/;  // 取得后面不是数字的字母
console.log(str.match(reg));

使用断言限制用户名关键词

<body>
    <input type="text" name="username" id="username">

    <script>
        const username = document.querySelector("[name='username']");
        username.addEventListener("keyup", function(){
            const reg = /^(?!.*lee.*)[a-z]{5,6}$/i;
            console.log(reg.test(this.value));
        });
    </script>
</body>

23. ?<!负向后行断言(前面不是什么的)

下面代码匹配前面不是hello的数字

let str = "hello123world456";
let reg = /(?<!hello)\d+/gi;
console.log(str.match(reg));

24. 使用断言排除法统一数据

<body>
    <main>
        <a href="https://www.baidu.com/1.jpg">1.jpg</a>
        <a href="https://oss.hello.com/2.jpg">2.jpg</a>
        <a href="https://cdn.world.com/3.jpg">3.jpg</a>
        <a href="https://haha.com/4.jpg">4.jpg</a>
    </main>

    <script>
        const main = document.querySelector("main");
        const reg = /https:\/\/([a-z]+)?(?<!oss)\..+?(?=\/)/gi; // 排除掉开头是oss的地址,把不是oss开头的地址替换为https://oss.bestcdn.com
        main.innerHTML = main.innerHTML.replace(reg, v => {
            return 'https://oss.bestcdn.com';
        });
    </script>
</body>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值