正则表达式的从入门到入土 含案例

本文含有: 原子组 断言匹配 禁止贪婪 命名捕获 ?= ?<= ?! ?<! ?<关键字>

才发现一直没有给正则表达式写个博文,今天正好有空来写写。因为JS比较方便测试,打开个网页就可以了,所以下面代码就以JS为基础写。

创建

  • 元字符必须转义:{}[]\^$|()?*+.
  • 转义字符:\

采用字面量创建:var 变量 = /正则表达式/匹配模式

RegExp该类型支持正则表达式,可以创建一个正则表达式

// 下面两种方法是等价的
// 匹配[bc]at,不区分大小写
var pattern4 = /\[bc\]at/i
var pattern6 = new RegExp("\\[bc\\]at", "i")

模式

  • g:表示匹配所有字符串,应用于所有字符串,不会在匹配到第一个时结束
let str = "The rain in Spain stays mainly in the plain";
let regex = /in/g;
let matches = str.match(regex);
console.log(matches); // 输出: [ 'in', 'in', 'in' ]
  • i:不区分大小写
// 匹配含有 hello 的字符串
let str = "Hello World";
let regex = /hello/i;
let result = regex.test(str);
console.log(result); // 输出: true
  • m:单行匹配匹配
    • 一行一行去匹配
    • 影响 ^$ 的行为,使它们匹配每一行的开头和结尾,而不仅仅是整个字符串的开头和结尾。
// 匹配开头为 Second 的字符串
let str = "First line\nSecond line";
let regex = /^Second/m;
let result = regex.test(str);
console.log(result); // 输出: true
  • s:忽略换行符
    • 使 . 可以匹配包括换行符在内的任何字符。
let str = "Hello\nWorld";
let regex = /Hello.World/s;
let result = regex.test(str);
console.log(result); // 输出: true

规则

这里就不一一演示了,自己试一下就可以,主要看下一章的案例

  1. |:或的意思,例如检查字符串是否存在a或b,/a|b/

  2. []:里的内容也是或的关系,原子表 [ab] == a|b[a-z]:任意小写字母;[A-Z]任意大写字母;[A-z]任意字母;[0-9] 任意数字

  3. [^]:除了,例:[^ae]>不选择a和e字母

  4. ():优先级

  5. {n}:出现n次;{m,n}:出现m到n次;m,:出现m次以上

  6. +:至少一个,等价于{1,}

  7. *:0个或多个,等价于{0,}

  8. ?:0个或1个,等价于{0,1}https?表示s可能会不存在->http

  9. ^:匹配开头,例如检查一个字符串中是否以a开头/^a/

  10. $:匹配结尾,边界符

  11. .:除了换行符以外的所有字符

  12. \:转义,例如如果想表示点号则需要\.

  13. ?::表示不保留,(?:com|cn)意为我匹配这段但是不保留

\w:任意字母、数字、_ [A-z0-9_] \W:除了字母、数字、_ [^A-z0-9_] \d:任意的数字 [0-9] \D:除了数字 [^0-9] \s:匹配任何空白字符,包括空格、制表符、换页符等等。 \S:匹配任何非空白字符。 \b:单词边界=>单词或非单词之间(意思是,该单词前面或后面不存在内容)看下面例子 \B:除了单词边界

例:创建一个正则表达式检查一个字符串中是否含有单词child=>/\bchild\b/—>'hello child'

例:去掉开头和结尾空格=>/^\s*|\s*$/g

匹配任意字符:(.*?)

字符串方法

  • string.search():搜索指定内容,返回其位置,找不到就-1
let str = "Hello, world!";
let position = str.search(/world/);
console.log(position); // 输出: 7
  • string.split():返回值是一个通过reg切分的数组, 参数二是长度
let str = "apple,banana,cherry";
let array = str.split(/,/);
console.log(array); // 输出: ["apple", "banana", "cherry"]

  • string.match():将符合条件的内容提取出来
let str = "The rain in Spain stays mainly in the plain";
let matches = str.match(/ain/g);
console.log(matches); // 输出: ["ain", "ain", "ain"]
  • string.replace():将字符串中指定内容替换为新的内容,两个参数,替换内容和新内容。
let str = "Hello, world!";
let newStr = str.replace("world", "universe");
console.log(newStr); // 输出: "Hello, universe!"

正则表达式方法

  • test():按规则查找,返回true和false
let regex = /hello/i;
let result = regex.test("Hello, world!");
console.log(result); // 输出: true
  • exec():返回包含第一个匹配项信息的数组,没有匹配项返回null。
    • 有两个格外属性:index(匹配项在字符串的位置)和input(字符串)
let regex = /h(ell)o/;
let result = regex.exec("Hello, world!");
console.log(result);
// 输出: ["Hello", "ell"]
// result.index: 0
// result.input: "Hello, world!"
  • 下面的就有点特殊,他们都是RegExp的函数。你需要先运行1+个的正则表达式匹配方法才能使用下面函数。
    • lastMatch:最近一次匹配项
    • lastParen:最近一次匹配的捕获组
    • leftContext:字符串中lastMatch之前的文本
    • multiline:布尔值、是否是多行模式
    • rightContext:字符串中lastMatch之后的文本
let regex = /(foo)bar/;
let str = "foobar";
regex.test(str); // 或者使用 regex.exec(str);

console.log(RegExp.lastMatch); // 输出: "foobar"
console.log(RegExp.lastParen); // 输出: "foo"
console.log(RegExp.leftContext); // 输出: ""
console.log(RegExp.rightContext); // 输出: ""
console.log(RegExp.multiline); // 输出: false
  • 小总结
    • test检查指定字符串是否存在
    • exec和match都可以获取值,区别一个是正则表达式的方法,一个是字符串的方法

进阶用法

原子组

如果你要获取某个地方的东西,那就给他个(),例如这样

在 replace中可以通过$2获取到第二个原子组((\w+))的信息

// 我希望获取到标签名以及标签内容
let str = '<h1>123</h1>'
let reg = /<(h[1-6])>(\w+)<\/h1>/

// 将整个标签替换为标签的内容
console.log(str.replace(reg, '$2')) // 123

str.replace(reg, (p0, p1, p2) => {
  // p0 = <h1>123</h1>
  // p1 = h1
  // p2 = 123
  console.log(p0, p1, p2)
})

console.log(str.match(reg)[2]) // 123
  • $&: 代表自己
let str = '<a href=<123>456>789>'
main.innerHTML.replace(/替换/g. `<a href="#">已被$&</a>`)
// 页面会显示为:已被替换
  • 忽略原子组: ?:
let str = '<h1>123</h1>'
let reg = /<(?:h[1-6])>(\w+)<\/h1>/

console.log(str.match(reg)[1]) // 123

断言匹配

断言简单来说就是根据条件筛选出特点的符合条件的内容

?= /条件(?=内容)/ // 匹配出后面具有某内容的条件
?<= /(?<=内容)条件/ // 匹配出前面具有某内容的条件
?! /条件(?!内容)/ // 匹配出后面不具有某内容的条件
?<! /(?<!内容)条件/ // 匹配出前面不具有某内容的条件
  • ?=: 匹配出后面具有某内容的条件
let str = "你知道么555啦啦啦";
const reg = /\d+(?=啦)/;
console.log(reg.exec(str)); // 555
  • ?<=: 匹配出前面具有某内容的条件
// 前面第一个字是关键字 "么" ,那么返回这段数字
let str = "你知道么555啦啦啦";
const reg = /(?<=么)\d+/;
console.log(reg.exec(str)); // 555

其他

  • 禁止贪婪
    • ?
    • 第一次匹配成功,就不再往后匹配了
let str = '<a href=<123>456>789>'
console.log(str.match(/<a href=<(.*)>/)) // 123>456>789
console.log(str.match(/<a href=<(.*?)>/)) // 123
  • 命名捕获
    • ?<关键字>,使用$<关键字>捕获
const reg = /<h1>(?<text>.*)<\/h2>/
let str = '<h1>baidu</h1>'
console.log(str.replace(reg, '<h2>$<text></h2>')) // <h1>baidu</h1>

案例

  • 限定用户名输入的长度只能是6-10位字母,数字,下划线
// 限定用户名输入的长度只能是6-10位字母,数字,下划线
let reg = /^[a-z0-9_]{6,10}$/i
  • 驼峰格式替换
// 驼峰格式替换
let str = "get-element-by-id";
let reg = /-\w/g;
str = str.replace(reg, (res) => {
  return res[1].toUpperCase();
});
console.log(str); // getElementById
  • 满足xxxx-xx-xx或者xxxx/xx/xx的都符合日期格式要求
// 满足xxxx-xx-xx或者xxxx/xx/xx的都符合日期格式要求
let date1 = "2021/04/01"
let date2 = "2021-04-01"
let reg = /^\d{4}([-/])\d{2}\1\d{2}$/
console.log(reg.test(date1)); // true
console.log(reg.test(date2)); // true
  • 对下面三个链接进行替换,把不是https的替换成https,没有www的添加www
// 对下面三个链接进行替换,把不是https的替换成https,没有www的添加www
let a1 = "http://www.baidu.com"
let a2 = "http://www.taobao.com"
let a3 = "https://jd.com"
let arr = [a1, a2, a3]
let reg = /(https?)(:\/\/)(www.)?(.*)/ig

let res = arr.map(item => {
    return item.replace(reg, (...args) => {
        args[1] = args[1] === "http" ? "https" : args[1]
        args[3] = args[3] || "www."
        return args.splice(1,4).join("")
    })
})

console.log(res) // ["https://www.baidu.com", "https://www.taobao.com", "https://www.jd.com"]
  • 把下面的h1,h2标签替换成p标签
// 把下面的h1,h2标签替换成p标签
let dom = `
    <h1>ychizzz</h1>
    <span>chizzz</span>
    <h2>YCHIZZZ</h2>
    `
let reg = /<(h[1-6])>([\s\S]+)<\/\1>/ig
// 此处的args从第1项开始代表了每个组,因为正则里表示内容的组([\s\S])是第二个,因此取args[2]
dom.replace(reg, (...args) => `<p>args[2]</p>`)
  • 密码验证,大小写字母
input.addEventListener('keyup', e => {
  const value = e.target.value
  let r = [/^[a-z]{5,10}$/i, /[A-Z]/, /[0-9]]/]
  let state = r.every(e => e.test(value))
  console.log(state ? 'yes' : 'no')
})
  • 只获取中文
let str = '你好世界! Hello World 你好'
let reg = /[^\w\!\s]+/g
let reg2 = /\p{sc=Han}+/gu
console.log(str.match(reg2)) // [ '你好世界', '你好' ]
Licensed under CC BY-NC-SA 4.0
本博客已稳定运行
发表了53篇文章 · 总计28.17k字
使用 Hugo 构建
主题 StackJimmy 设计