javascript正则表达式

272 阅读3分钟

"." 代表所有字符,但是不包括换行 它是包括空格的

“+” 匹配前面的子表达式一次或多次 (次数 >= 1,即至少1次)

“*” 表示字符串1和字符串2中间有任意个数的东西

“?” abc?de: 表示可匹配的字符串为 abde (匹配0次c) 或 abcde (匹配1次c)。 有c也可以没有c也可以 /favou?rite/g 匹配u或者不匹配u

“^”字符串开头

“$”搜索字符串的末尾

let caboose = "The last car on a train is the caboose";
let lastRegex = /caboose$/; // Change this line
let result = lastRegex.test(caboose);

^起始 $结束 边界符

 let input1=document.querySelector(`[name="phonenumber"]`).addEventListener("keyup",function(){
                  //13 15 18 start
                  veg1=/^(13|15|18)\d{8,13}$/;
                  console.log(veg1.test(this.value));
                })

\w 字母数字下划线

\W

\W 与 \w 相反,表示这个位置的字符既不是字母、数字,也不是下划线。 也就是:特殊符号(除下划线),或者空格等满足。 12\w45:则表示12和45中间必须是一个字母,数字,或下划线。

\s匹配空格

\S不匹配空格

{下限,上限}
{指定确切的数字}

\d 数字0-9 表示一个数字。 它在位置输入的值必须是一个数字

\D 表示一个非数字,它和上面 \d 的意思恰好相反。

\用来转义 比如我们需要使用一个字符,但是它是正则里面的,所以我们要使用转义 对于\d这样的带斜杠的,我们转义时要打两个斜杠\

\p{里面写L ,P} 代表只匹配什么

查找语言系统

\p{sc='Han'} 查找汉语

还有很多语言,可参考MDN文档

L:只匹配英文

P:只匹配标点符号

模式修正符

s 视为单行匹配 当遇到换行时使用它可忽视换行

i 忽略大小写

g 全部返回

m 每一行单独处理

u 使用 unicode 码的模式进行匹配。这样就不会出现乱码

y 当执行exec()方法时不会忽略匹配不到字符 和g类似 匹配从目标字符串的当前位置开始

实例:只取域名

let input=`https://www.nihao.com
http://hello.com`;
			 //只取域名
	 let veg=/https?:\/\/((?:\w+\.)?\w+\.(?:com|cn|arg))/gi//在嵌套分组里面不记录
				 let urls=[];
				 while((res=veg.exec(input))){
						urls.push(res[1]);
						 }
	 console.dir(urls);

原子表

”[ ]“ 按单一字符匹配 返回的是字符串

let input=`2023-2-6`;
     let reg=/^\d{4}([-\/])\d{2}\1\d{2}$/;

     let qq=[];
    console.log(input.match(reg));

原子表特殊字符

放在原子表里面任何特殊字符都是字符串

使用原子表匹配所有字符

[\s\S] [\d\D] 这两个都可以匹配所有字符,因为"."匹配时不会包括换行,但是使用他们可以

原子组( )

组编号

\1 \2 。。。。。

有重复的地方就直接对应

也可以取别名编号

原子组别名

<别名>

使用时要加上?

 //给组起别名<>
        let hd=`
        <h1>nihao</h1>
        <span>你好</span>
        <h2>hdcms</h2>
        `;
        const reg=/<(h[1-6])>(<con>*?)<\/\1>/gi;
            console.log(hd.replace(reg,"<h4>$<con></h4>"))
            //使用别名优化原子组
            const main=document.querySelector("body main").innerHTML;
            const reg=/<a.*?href=(["'])(?<link>.*)\1>(?<title>.*?)/;
                const links=[];
                for(const iterator of main.matchAll(reg)){
                    links.push(iterator["groups"]);
                }
                console.log(links);

替换操作

p0 全部内容

p1 第一个

p2...

()+ 这里的加号是相对于整个原子组的hd一个或者多个匹配

原子组在替换中的使用技巧

 const main=document.querySelector("body main");
        const reg=/(<a.*href=['"])(http)(:\/\/)(www\.)?(houdunren|baidu)/i;
        main.innerHTML=main.innerHTML.replace(reg,(v,...args)=>{
            args[1]+="s";
            args[3]=args[3]||"www.";
            return args.splice(0,5).join("");
        })

","分隔符 一个字符串匹配多个正则

 let input3=document.querySelector(`[name="name"]`).addEventListener("keyup",(e)=>{
                     const value=e.target.value;
                     const evg3=[/^[a-z]{2,6}$/ig,/[A-Z]/]//这里的字符串需要同时满足两组正则
                     let state=evg3.every(e=>e.test(value));
                     console.log(state?"正确":"错误");
              })

| 或者

 let input1=document.querySelector(`[name="phonenumber"]`).addEventListener("keyup",function(){
                  //13 15 18 start
                  veg1=/^(13|15|18)\d{8,13}$/;
                  console.log(veg1.test(this.value));
                })

区间匹配

[0-9]

[a-z]

只能写升序

排除匹配

[^ue] 除了u和e

不记录分组

?:

多种重复匹配

"*" + {n1,n2} ? 他们·都是都是贪婪的

如果使用贪婪模式会让一些恶意攻击者钻空子,他们仅需要写一个容易产生回溯行为的字符串导致请求堆积导致雪崩,无法响应新的请求,我们应该禁止使用贪婪模式

<span>nihao</span>
        <span>hello</span>
        <span>world</span>
        <script>
        const main=document.querySelector("main");
        const reg=/<span>([\s\S]+?)<\/span>/ig;//在会产生多种重复匹配的符合后加上?,它代表0次或者多次,这样就不会产生贪婪模式
         
            main.innerHTML=main.innerHTML.replace(reg,(v,p1)=>{
                return`<h4 style="color:red" >你好哇-${p1}</h4>`
            })
    </script>

match() 它和matchAll()的区别是不能返回组的序号

全局匹配

在新版的浏览器有方法

matchAll() 其实返回的是一个迭代器

 let reg=/(<h[1-6]>)([\s\S]+?)<\/\1>/gi;
        const body=document.querySelector("body");
        const hd=body.innerHTML.matchAll(reg);
        let content=[];
        for(let iterator of hd){
            content.push(iterator[1]);
        }
        console.log(content);

为低端浏览器写全局匹配

 为低端浏览器写matchAll()方法
        String.prototype.matchAll=function(reg){
            let res=this.match(reg);
            if(res){
                let str=this.replace(res[0],"^".repeat(res[0].length));
                let match=str.matchAll(reg)||[];//查不到就设置为空
                return [res,...match];
            }
        }
        let body =document.querySelector("body").innerHTML;
        let search=body.matchAll(/<(h[1-6])>([\s\S]+?)<\/\1>/i);
        console.log(search);

replace() 字符串的替换

下面的可以用于replace()方法内进行替换操作

$1-n 指的是原子组

$& 代表匹配的内容(在表达式当中\0)

 $`代表前面的内容
 $' 代表后面的内容

split("里面是要使用的间隔符(可以使用正则)")

提取网址

  let string=document.querySelector(`[name="input"]`);
        let result=[];
     string.addEventListener("keyup",function (){
        let reg=/^(https?:\/\/)(\w+\.)?(\w+\.)+(com|cn|org|cc)$/g;
       console.log(reg.test(string))
        let hd=string.matchAll(reg);
        for(ints of hd){
            result.push(hd);
        }
        console.dir(result);
      })

用exec()匹配全局

全局匹配这个正则 可以用来统计次数,它返回的是数组

在字符串中执行查找匹配的 RegExp 方法,它返回一个数组(未匹配到则返回 null)

  //用exec()匹配全局
        function search (string,reg){
        let result=[];
        while(res=reg.exec(string)){
            result.push(res);
        }
        return result;
        }
       let matchs= search(document.querySelector("body").innerHTML,/<(h[1-6])>([\s\S]+?)<\/\1>/gi);
       //为什么要加上g,以为exec()只会返回一个值后面就会停止,不返回全局就会一直停留在一个值上面
       console.dir(matchs);

test()

验证字符串是否匹配正则 返回false 或者true

断言匹配

?=(先行断言) 条件语句 /你好(?=世界)/g 它这里会要求“你好”的后面必须是“世界”才会符合这个正则 但是“世界”不是匹配结果的一部分,当我们打印符合这个正则的字符串它不会返回"世界"

?<=(后行断言) 前面必须有什么 和先行断言类似 利用被断言的部分不会成为匹配结果这个特性,我们可以做模糊号码等业务

?! 后面不是什么 仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找。

实例 使用断言限制用户名关键字

(?!.关键字.) 这样无论关键字在前面还是后面都不会匹配到

?<! 前面不是什么 仅仅当'x'前面不是'y'时匹配'x',这被称为反向否定查找。 实例

使用断言规范价格

 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";//如果我们找不到多少元就给他加上.00就会有了
            return args.splice(0,2).join("");
          
         })
         console.log(lessons);

使用断言模糊电话号码

  //使用断言模糊电话号码
       let users=`
       MyPhoneNumber:1232425361111
        myMontherPhoneNumber:111111111111
       `;
       let reg=/\d+(?![a-z])/gi;
       users=users.replace(reg,(v)=>{
        return "*".repeat(4);
       })
       console.log(users);

使用断言来限定用户名关键字

 //使用断言来限定用户名关键字
  const input=document.querySelector(`[name="username"]`);
  input.addEventListener("keyup",function(){
    const reg=/^(?!.*你好.*)[a-z]{5,6}$/i;//(?!.*关键字.*)  这样无论关键字在前面还是后面都不会匹配到
   console.log(this.value.match(reg));
  })

总练习:

该代码取自MDN文档

当用户输入指定的电话号码格式时,弹出字符串

当用户输入错误时,又弹出提示的内容



  <body>
    <p>Enter your phone number (with area code) and then click "Check".
        <br>The expected format is like ###-###-####.</p>
    <form action="#">
      <input id="phone"  placeholder="111-/.111-/.1111" ><button onclick="testInfo(document.getElementById('phone'));">Check</button>
    </form>
  </body>

  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <meta http-equiv="Content-Script-Type" content="text/javascript">
    <script type="text/javascript">
      var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;//三位数字-/.三位数字4位数字
      function testInfo(phoneInput) {
        var OK = re.exec(phoneInput.value);
        if (!OK)
          window.alert(phoneInput.value + ' isn\'t a phone number with area code!');
        else
          window.alert('Thanks, your phone number is ' + OK[0]);
      }
    </script>
  </head>