js正则表达式

正则表达式是用于匹配字符串中字符组合的模式,在 JavaScript中,正则表达式也是对象。

  • 正则表达式是在宿主环境下运行的,如js/php/node.js 等
  • 本章讲解的知识在其他语言中知识也是可用的,会有些函数使用上的区别

一、创建正则

字面量创建

使用//包裹的字面量创建方式是推荐的作法,但它不能在其中使用变量

let hd = "houdunren.com";
let a = "u";
console.log(/a/.test(hd)); //false

在字面量中也可以使用变量,但是比较麻烦,所以有变量时建议使用下面的对象创建方式
let hd = "houdunren.com";
let a = "u";
console.log(eval(`/${a}/`).test(hd)); //true

对象创建

let hd = "houdunren.com";
let web = "houdunren";
let reg = new RegExp(web);
console.log(reg.test(hd)); //true

通过对象创建正则提取标签
var tag = 'h1';
let reg = new RegExp("<(" + tag + ")>.+</\\1>", "g");

二、基础知识

1、选择符

| 这个符号带表选择修释符,也就是 | 左右两侧有一个匹配到就可以。

检测电话是否是上海或北京的坐机

let tel = "010-12345678";
//错误结果:只匹配 | 左右两边任一结果
console.log(tel.match(/010|020\-\d{7,8}/)); 

//正确结果:所以需要放在原子组中使用
console.log(tel.match(/(010|020)\-\d{7,8}/));

2、字符转义

转义用于改变字符的含义,用来对某个字符有多种语义时的处理。

假如有这样的场景,如果我们想通过正则查找/符号,但是 /在正则中有特殊的意义。如果写成///这会造成解析错误,所以要使用转义语法 /\//来匹配。

const url = "https://www.houdunren.com";
console.log(/https:\/\//.test(url)); //true

3、字符边界

使用字符边界符用于控制匹配内容的开始与结束约定。

边界符说明
^匹配字符串的开始
$匹配字符串的结束,忽略换行符
匹配内容必须以www开始
const hd = "www.houdunren.com";
console.log(/^www/.test(hd)); //true

匹配内容必须以.com结束
const hd = "www.houdunren.com";
console.log(/\.com$/.test(hd)); //true

三、元子字符

元字符是正则表达式中的最小元素,只代表单一(一个)字符

字符列表

元字符说明示例
\d匹配任意一个数字[0-9]
\D与除了数字以外的任何一个字符匹配[^0-9]
\w与任意一个英文字母,数字或下划线匹配[a-zA-Z_]
\W除了字母,数字或下划线外与任何字符匹配[^a-zA-Z_]
\s任意一个空白字符匹配,如空格,制表符\t,换行符\n[\n\f\r\t\v]
\S除了空白符外任意一个字符匹配[^\n\f\r\t\v]
.匹配除换行符外的任意字符

#使用体验

匹配任意数字

let hd = "houdunren 2010";
console.log(hd.match(/\d/g)); //["2", "0", "1", "0"]

使用/s视为单行模式(忽略换行)时,. 可以匹配所有

let hd = `
  <span>
    houdunren
    hdcms
  </span>
`;
let res = hd.match(/<span>.*<\/span>/s);
console.log(res[0]);

正则中空格会按普通字符对待

let tel = `010 - 999999`;
console.log(/\d+-\d+/.test(tel)); //false
console.log(/\d+ - \d+/.test(tel)); //true

所有字符

可以使用 [\s\S] 或 [\d\D] 来匹配所有字符

let hd = `
  <span>
    houdunren
    hdcms
  </span>
`;
let res = hd.match(/<span>[\s\S]+<\/span>/);
console.log(res[0]);

四、模式修饰

正则表达式在执行时会按他们的默认执行方式进行,但有时候默认的处理方式总不能满足我们的需求,所以可以使用模式修正符更改默认方式。

修饰符说明
i不区分大小写字母的匹配
g全局搜索所有匹配内容
m视为多行
s视为单行忽略换行符,使用. 可以匹配所有字符
y从 regexp.lastIndex 开始匹配
u正确处理四个字符的 UTF-16 编码

i

将所有houdunren.com 统一为小写

let hd = "houdunren.com HOUDUNREN.COM";
hd = hd.replace(/houdunren\.com/gi, "houdunren.com");
console.log(hd);

g

使用 g 修饰符可以全局操作内容

let hd = "houdunren";
hd = hd.replace(/u/, "@");
console.log(hd); //没有使用 g 修饰符是,只替换了第一个

let hd = "houdunren";
hd = hd.replace(/u/g, "@");
console.log(hd); //使用全局修饰符后替换了全部的 u

m

用于将内容视为多行匹配,主要是对 ^和 $ 的修饰

将下面是将以 #数字开始的课程解析为对象结构,学习过后面讲到的原子组可以让代码简单些

let hd = `
  #1 js,200元 #
  #2 php,300元 #
  #9 houdunren.com # 后盾人
  #3 node.js,180元 #
`;
// [{name:'js',price:'200元'}]
let lessons = hd.match(/^\s*#\d+\s+.+\s+#$/gm).map(v => {
  v = v.replace(/\s*#\d+\s*/, "").replace(/\s+#/, "");
  [name, price] = v.split(",");
  return { name, price };
});
console.log(JSON.stringify(lessons, null, 2));

五、原子表

在一组字符中匹配某个元字符,在正则表达式中通过元字符表来完成,就是放到[] (方括号)中。

使用语法

原子表说明
[]只匹配其中的一个原子
[^]只匹配"除了"其中字符的任意一个原子
[0-9]匹配0-9任何一个数字
[a-z]匹配小写a-z任何一个字母
[A-Z]匹配大写A-Z任何一个字母

使用[]匹配其中任意字符即成功,下例中匹配ue任何一个字符,而不会当成一个整体来对待

const url = "houdunren.com";
console.log(/ue/.test(url)); //false
console.log(/[ue]/.test(url)); //true
获取0~3间的任意数字
const num = "2";
console.log(/[0-3]/.test(num)); //true

匹配a~f间的任意字符
const hd = "e";
console.log(/[a-f]/.test(hd)); //true

六、原子组

  • 如果一次要匹配多个元子,可以通过元子组完成
  • 原子组与原子表的差别在于原子组一次匹配多个元子,而原子表则是匹配任意一个字符
  • 元字符组用 () 包裹

下面使用原子组匹配 h1 标签,如果想匹配 h2 只需要把前面原子组改为 h2 即可。

\\   \1 代表原子组中的h1
const hd = `<h1>houdunren.com</h1>`;
console.log(/<(h1)>.+<\/\1>/.test(hd)); //true

基本使用

没有添加 g 模式修正符时只匹配到第一个,匹配到的信息包含以下数据

变量说明
0匹配到的完整内容
1,2....匹配到的原子组
index原字符串中的位置
input原字符串
groups命名分组

match中使用原子组匹配,会将每个组数据返回到结果中

  • 0 为匹配到的完成内容
  • 1/2 等 为原子级内容
  • index 匹配的开始位置
  • input 原始数据
  • groups 组别名
let hd = "houdunren.com";
console.log(hd.match(/houdun(ren)\.(com)/)); 
//["houdunren.com", "ren", "com", index: 0, input: "houdunren.com", groups: undefined]

下面使用原子组匹配标题元素

let hd = `
  <h1>houdunren</h1>
  <span>后盾人</span>
  <h2>hdcms</h2>
`;

console.table(hd.match(/<(h[1-6])[\s\S]*<\/\1>/g));

检测 0~100 的数值,使用 parseInt 将数值转为10进制

console.log(/^(\d{1,2}|100)$/.test(parseInt(09, 10)));

#邮箱匹配

下面使用原子组匹配邮箱

let hd = "2300071698@qq.com";
let reg = /^[\w\-]+@[\w\-]+\.(com|org|cn|cc|net)$/i;
console.dir(hd.match(reg));

如果邮箱是以下格式 houdunren@hd.com.cn 上面规则将无效,需要定义以下方式

let hd = `admin@houdunren.com.cn`;
let reg = /^[\w-]+@([\w-]+\.)+(org|com|cc|cn)$/;
console.log(hd.match(reg));

#引用分组

\n 在匹配时引用原子组, $n 指在替换时使用匹配的组数据。下面将标签替换为p标签

let hd = `
  <h1>houdunren</h1>
  <span>后盾人</span>
  <h2>hdcms</h2>
`;

let reg = /<(h[1-6])>([\s\S]*)<\/\1>/gi;
console.log(hd.replace(reg, `<p>$2</p>`));

如果只希望组参与匹配,便不希望返回到结果中使用 (?: 处理。下面是获取所有域名的示例

let hd = `
  https://www.houdunren.com
  http://houdunwang.com
  https://hdcms.com
`;

let reg = /https?:\/\/((?:\w+\.)?\w+\.(?:com|org|cn))/gi;
while ((v = reg.exec(hd))) {
  console.dir(v);
}

#分组别名

如果希望返回的组数据更清晰,可以为原子组编号,结果将保存在返回的 groups字段中

let hd = "<h1>houdunren.com</h1>";
console.dir(hd.match(/<(?<tag>h[1-6])[\s\S]*<\/\1>/));

组别名使用 ?<> 形式定义,下面将标签替换为p标签

let hd = `
  <h1>houdunren</h1>
  <span>后盾人</span>
  <h2>hdcms</h2>
`;
let reg = /<(?<tag>h[1-6])>(?<con>[\s\S]*)<\/\1>/gi;
console.log(hd.replace(reg, `<p>$<con></p>`));

获取链接与网站名称组成数组集合

<body>
  <a href="https://www.houdunren.com">后盾人</a>
  <a href="https://www.hdcms.com">hdcms</a>
  <a href="https://www.sina.com.cn">新浪</a>
</body>

<script>
  let body = document.body.innerHTML;
  let reg = /<a\s*.+?(?<link>https?:\/\/(\w+\.)+(com|org|cc|cn)).*>(?<title>.+)<\/a>/gi;
  const links = [];
  for (const iterator of body.matchAll(reg)) {
    links.push(iterator["groups"]);
  }
  console.log(links);
</script>

七、重复匹配

如果要重复匹配一些内容时我们要使用重复匹配修饰符,包括以下几种。

符号说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次

下面是验证坐机号的正则

let hd = "010-12345678";
console.log(/0\d{2,3}-\d{7,8}/.exec(hd));

禁止贪婪

正则表达式在进行重复匹配时,默认是贪婪匹配模式,也就是说会尽量匹配更多内容,但是有的时候我们并不希望他匹配更多内容,这时可以通过?进行修饰来禁止重复匹配

使用说明
*?重复任意次,但尽可能少重复
+?重复1次或更多次,但尽可能少重复
??重复0次或1次,但尽可能少重复
{n,m}?重复n到m次,但尽可能少重复
{n,}?重复n次以上,但尽可能少重复

下面是禁止贪婪的语法例子

let str = "aaa";
console.log(str.match(/a+/)); //aaa
console.log(str.match(/a+?/)); //a
console.log(str.match(/a{2,3}?/)); //aa
console.log(str.match(/a{2,}?/)); //aa

下面是使用禁止贪婪查找页面中的标题元素

<body>
  <h1>
    houdunren.com
  </h1>
  <h2>hdcms.com</h2>
  <h3></H3>
  <H1></H1>
</body>

<script>
  let body = document.body.innerHTML;
  let reg = /<(h[1-6])>[\s\S]*?<\/\1>/gi;
  console.table(body.match(reg));
</script>

八、正则方法

test      返回bool类型

检测输入的邮箱是否合法

<body>
  <input type="text" name="email" />
</body>

<script>
  let email = document.querySelector(`[name="email"]`);
  email.addEventListener("keyup", e => {
    console.log(/^\w+@\w+\.\w+$/.test(e.target.value));
  });
</script>

exec

不使用 g 修饰符时与 match 方法使用相似,使用 g 修饰符后可以循环调用直到全部匹配完。

  • 使用 g 修饰符多次操作时使用同一个正则,即把正则定义为变量使用
  • 使用 g 修饰符最后匹配不到时返回 null

计算内容中后盾人出现的次数

<body>
  <div class="content">
    后盾人不断分享视频教程,后盾人网址是 houdunren.com
  </div>
</body>

<script>
  let content = document.querySelector(".content");
  let reg = /(?<tag>后盾)人/g;
  let num = 0;
  while ((result = reg.exec(content.innerHTML))) {
    num++;
  }
  console.log(`后盾人共出现${num}次`);
</script>

九、字符串方法

search() 方法用于检索字符串中指定的子字符串,也可以使用正则表达式搜索,返回值为索引位置

let str = "houdunren.com";
console.log(str.search("com"));

使用正则表达式搜索

console.log(str.search(/\.com/i));

match

直接使用字符串搜索

let str = "houdunren.com";
console.log(str.match("com"));

使用正则获取内容,下面是简单的搜索字符串

let hd = "houdunren";
let res = hd.match(/u/);
console.log(res);
console.log(res[0]); //匹配的结果
console.log(res[index]); //出现的位置

matchAll

在新浏览器中支持使用 matchAll 操作,并返回迭代对象

let str = "houdunren";
let reg = /[a-z]/ig;
for (const iterator of str.matchAll(reg)) {
  console.log(iterator);
}

split

用于使用字符串或正则表达式分隔字符串,下面是使用字符串分隔日期

let str = "2023-02-12";
console.log(str.split("-")); //["2023", "02", "12"]

如果日期的连接符不确定,那就要使用正则操作了

let str = "2023/02-12";
console.log(str.split(/-|\//));

replace

replace 方法不仅可以执行基本字符替换,也可以进行正则替换,下面替换日期连接符

let str = "2023/02/12";
console.log(str.replace(/\//g, "-")); //2023-02-12

十、断言匹配

断言虽然写在扩号中但它不是组,所以不会在匹配结果中保存,可以将断言理解为正则中的条件。

#(?=exp)

零宽先行断言 ?=exp 匹配后面为 exp 的内容

把后面是教程 的后盾人汉字加上链接

<body>
  <main>
    后盾人不断分享视频教程,学习后盾人教程提升编程能力。
  </main>
</body>

<script>
  const main = document.querySelector("main");
  const reg = /后盾人(?=教程)/gi;
  main.innerHTML = main.innerHTML.replace(
    reg,
    v => `<a href="https://houdunren.com">${v}</a>`
  );
</script>

下面是将价格后面 添加上 .00

<script>
  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);
</script>

使用断言验证用户名必须为五位,下面正则体现断言是不是组,并且不在匹配结果中记录

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

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

#(?<=exp)

零宽后行断言 ?<=exp 匹配前面为 exp 的内容

匹配前面是houdunren 的数字

let hd = "houdunren789hdcms666";
let reg = /(?<=houdunren)\d+/i;
console.log(hd.match(reg)); //789

匹配前后都是数字的内容

let hd = "houdunren789hdcms666";
let reg = /(?<=\d)[a-z]+(?=\d{3})/i;
console.log(hd.match(reg));

所有超链接替换为houdunren.com

<body>
  <a href="https://baidu.com">百度</a>
  <a href="https://yahoo.com">雅虎</a>
</body>
<script>
  const body = document.body;
  let reg = /(?<=<a.*href=(['"])).+?(?=\1)/gi;
  // console.log(body.innerHTML.match(reg));
  body.innerHTML = body.innerHTML.replace(reg, "https://houdunren.com");
</script>

下例中将 后盾人 后面的视频添加上链接

<body>
  <h1>后盾人视频不断录制案例丰富的视频教程</h1>
</body>

<script>
  let h1 = document.querySelector("h1");
  let reg = /(?<=后盾人)视频/;
  h1.innerHTML = h1.innerHTML.replace(reg, str => {
    return `<a href="https://www.houdunren.com">${str}</a>`;
  });
</script>

将电话的后四位模糊处理

let users = `
  向军电话: 12345678901
  后盾人电话: 98745675603
`;

let reg = /(?<=\d{7})\d+\s*/g;
users = users.replace(reg, str => {
  return "*".repeat(4);
});
console.log(users); //向军电话: 1234567****后盾人电话: 9874567****

获取标题中的内容

let hd = `<h1>后盾人视频不断录制案例丰富的视频教程</h1>`;
let reg = /(?<=<h1>).*(?=<\/h1>)/g;
console.log(hd.match(reg));

#(?!exp)

零宽负向先行断言 后面不能出现 exp 指定的内容

使用 (?!exp)字母后面不能为两位数字

let hd = "houdunren12";
let reg = /[a-z]+(?!\d{2})$/i;
console.table(reg.exec(hd));

下例为用户名中不能出现向军

<body>
  <main>
    <input type="text" name="username" />
  </main>
</body>
<script>
  const input = document.querySelector(`[name="username"]`);
  input.addEventListener("keyup", function() {
    const reg = /^(?!.*向军.*)[a-z]{5,6}$/i;
    console.log(this.value.match(reg));
  });
</script>

#(?<!exp)

零宽负向后行断言 前面不能出现exp指定的内容

获取前面不是数字的字符

let hd = "hdcms99houdunren";
let reg = /(?<!\d+)[a-z]+/i;
console.log(reg.exec(hd)); //hdcms

把所有不是以 https://oss.houdunren.com 开始的静态资源替换为新网址

<body>
  <main>
    <a href="https://www.houdunren.com/1.jpg">1.jpg</a>
    <a href="https://oss.houdunren.com/2.jpg">2.jpg</a>
    <a href="https://cdn.houdunren.com/2.jpg">3.jpg</a>
    <a href="https://houdunren.com/2.jpg">3.jpg</a>
  </main>
</body>
<script>
  const main = document.querySelector("main");
  const reg = /https:\/\/(\w+)?(?<!oss)\..+?(?=\/)/gi;
  main.innerHTML = main.innerHTML.replace(reg, v => {
    console.log(v);
    return "https://oss.houdunren.com";
  });
</script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值