我猜你做项目也会遇到正则表达式相关的内容~

最近因为项目中有些地方需要正则,给我难受坏了,因为这东西看了就忘,用到就得查,属实难为人了,那今天菜鸟又粗略整理了一遍,以便之后用到翻看。文中有些例子和分类思路用到了网站中js知识的内容,如有更好的建议,诚恳发言,感谢大家!!!

正则表达式

js 复制代码
let regexp = new RegExp(pattern[模式],modifiers[修饰符])
let regexp = /pattern/modifiers 
【注】当使用构造函数创造正则对象时,需要常规的字符转义规则(在前面加反斜杠 \)
var re = new RegExp("\\w+");
var re = /\w+/;

修饰符

修饰符 说明
i 搜索时不区分大小写:A和a之间没区别
g 搜索时会寻找所有的匹配项(全局匹配)
m 多行匹配
s 启用"dotall"模式,允许点.匹配换行符\n
u 开启完整的Unicode支持,能够正确处理四个字节的UTF-16编码
y 粘滞模式,同g修饰符类似,都是全局匹配,但是y必须从剩余字符的第一个位置开始匹配,否则退出匹配

字符串方法

str.match(regexp)

  • match 查找匹配项并以数组形式返回,如果未查找到则返回null
  • 返回数组的内容依赖于regexp是否具有全局标志g
js 复制代码
let str = "We can do it, but we cannot say";
console.log(str.match(/we/)); // ['we',index: 18,input: 'We can do it, but we cannot say',groups: undefined]
console.log(str.match(/we/gi)); //[ 'We', 'we' ]
console.log(str.match(/hello/)); //null
// 【注】如果没有匹配项,则返回null,所以在需求为不匹配则返回空数组的应用中,多加一层判断
let result = 'JavaScript'.match(/vue/) || []
console.log(result, !result.length); // [] true

str.matchAll(regexp)

  • matchAll 它返回的不是数组,而是一个可迭代对象
  • 正则表达式的修饰符必须加g)它将每个匹配项以包含组的数组的形式返回
  • 如果没有匹配项,则返回的不是null,而是一个空的可迭代对象
js 复制代码
let str = "map tap nap"
let regexp = /[a-z]ap/g
console.log(Array.from(str.matchAll(regexp)));
// [
//   ['map', index: 0, input: 'map tap nap', groups: undefined],
//   ['tap', index: 4, input: 'map tap nap', groups: undefined],
//   ['nap', index: 8, input: 'map tap nap', groups: undefined]
// ]
let regexp1 = /mn/g
console.log(Array.from(str.matchAll(regexp1))); // []

regexp.exec(str)

  • exec 查找匹配项并以数组形式返回,如果未查找到则返回null
  • 无论有无g修饰,都返回第一个匹配的字符串;该方法还可以返回子匹配项
js 复制代码
let str = "We can do it, but we Can not say net";
let regexp = /can/g
let regexp1 = /hello/g
let regexp2 = /n([a-z]+)t/g
console.log(regexp.exec(str)); //['can',index: 3,input: 'We can do it, but we Can not say net',groups: undefined]
console.log(regexp1.exec(str)); //null 
console.log(regexp2.exec(str)); //['not','o',index: 25,input: 'We can do it, but we Can not say net',groups: undefined]
// exec只返回第一个匹配的字符串,如果想返回全部(借助while和g参数实现)
while (res = regexp2.exec(str)) {
  console.log(res);
  // [
  //   'not',
  //   'o',
  //   index: 25,
  //     input: 'We can do it, but we Can not say net',
  //     groups: undefined
  // ]
  // [
  //   'net',
  //   'e',
  //   index: 33,
  //   input: 'We can do it, but we Can not say net',
  //   groups: undefined
  // ]
}

str.search(regexp)

  • search 返回第一个匹配的字符串所在位置,偏移量从0开始
js 复制代码
let str = "We can do it, but we Can not say net";
console.log(str.search(/can/g)); //3
console.log(str.search(/we/i)); //0

str.replace(regexp,replacement)

  • replace 返回结果为替换第一个或所有匹配项之后新的字符串
js 复制代码
let str = "We can do it, but we can not say";
console.log(str.replace(/we/, '123')); //We can do it, but 123 can not say
console.log(str.replace(/we/gi, '123')); //123 can do it, but 123 can not say

第二个参数replacement是字符串,可以在其中使用特殊的字符组合来对匹配项进行插入:

符号 说明
$& 插入整个匹配项
$` 插入字符串中匹配项之前的字符串部分
$' 插入字符串中匹配项之后的字符串部分
$n n为数字,则插入第n个分组的内容
$ 插入带给定name的括号内的内容
$$ 插入字符$
js 复制代码
let str = "We can do it, but we can not say";
console.log(str.replace(/say/, "$&, you are so cute.")); // We can do it, but we can not say, you are so cute.

str.replaceAll(regexp,replacement)

  • replaceAll 返回替换所有匹配项之后的新的字符串
  • 当使用一个 regexp 时,必须设置全局("g")标志, 否则,它将引发 TypeError:"必须使用全局 RegExp 调用 replaceAll"。`
js 复制代码
let str = "We can do it, but we can not say";
console.log(str.replaceAll(/can/g, 123)); //We 123 do it, but we 123 not say

regexp.test(str)

  • test 用于寻找至少一个匹配项,找到了返回true,否则返回false
js 复制代码
let str = "We can do it, but we can not say";
let regexp = /NOT/i
let regexp1 = /NOT/
console.log(regexp.test(str)); // true 
console.log(regexp1.test(str)); // false 

str.split(separator[,limit])

  • split 用于把一个字符串分割成字符串数组
  • limit 用于限制分割后数组的长度
js 复制代码
let str = "a,b,c"
let regexp = /,/
console.log(str.split(regexp)); // [ 'a', 'b', 'c' ]

let str1 = "aa,bb:cc#dd@ee"
let regexp1 = /[,:#@]/
console.log(str1.split(regexp1, 2)); // [ 'aa', 'bb' ]
console.log(str1.split(regexp1, 3)); // [ 'aa', 'bb', 'cc' ]
console.log(str1.split(regexp1)); // [ 'aa', 'bb', 'cc', 'dd', 'ee' ]

语法

字符类

示例 说明
. 匹配除换行符以外的任何字符
\d 匹配数字:[0-9]
\D 匹配非数字:[^0-9]
\s 匹配空格字符:[\t\n\v\f\r]
\S 匹配非空格字符:[^\t\n\v\f\r]
\w 匹配单字字符:[A-Za-z0-9_]
\W 匹配非单字字符:[^A-Za-z0-9_]
js 复制代码
// 提取电话中纯数字 
let str = "+7(903)-123-45-67"
let regexp = /\d/g
console.log(str.match(regexp).join('')); //79031234567
console.log(str.replace(/\D/g, "")); //79031234567

// 正则同时包含常规符号和字符类 
let str1 = "Are you learning ES6?"
let regexp1 = /ES\d/
console.log(str1.match(regexp1)); // [ 'ES6', index: 17, input: 'Are you learning ES6?', groups: undefined ]

// 正则同时使用多个字符类进行匹配 
console.log(str1.match(/\s\w\w\d/)); // [' ES6',index: 16,input: 'Are you learning ES6?',groups: undefined]

// 点(.)匹配除换行符之外的任何字符
let regexp2 = /E.6/
console.log('ES6'.match(regexp2)); // [ 'ES6', index: 0, input: 'ES6', groups: undefined ]
console.log('E46'.match(regexp2)); // [ 'E46', index: 0, input: 'E46', groups: undefined ]
console.log('E 6'.match(regexp2)); // [ 'E 6', index: 0, input: 'E 6', groups: undefined ]
console.log('E$6'.match(regexp2)); // [ 'E$6', index: 0, input: 'E$6', groups: undefined ]
console.log('E6'.match(regexp2)); //null
console.log('E\n6'.match(regexp2)); //null

// 带有修饰符"s"时点字符类匹配任何字符
let regexp3 = /E.6/s
console.log('E\n6'.match(regexp3)); //[ 'E\n6', index: 0, input: 'E\n6', groups: undefined ]

锚点

【注】锚点本身宽度为零,它们并不匹配任一个具体的字符

示例 说明
^Demo 在字符串或内部行的开头匹配"Demo"
Demo$ 在字符串或内部行的结尾匹配"Demo"
js 复制代码
// 开头、结尾匹配
let str = "love and Peace"
console.log(/^love/.test(str)); // true 
console.log(/Peace$/.test(str)); // true 

// 开头、结尾+多行匹配模式m
let str2 = `1respect 
2encourage
3praise`
console.log(str2.match(/^\d/g)); // [ '1' ]
console.log(str2.match(/^\d/gm)); // [ '1', '2', '3' ]

词边界 \b

有三种不同的位置可作为词边界:

  • 在字符串开头,如果第一个字符是单词字符 \w
  • 在字符串中的两个字符之间,其中一个是单词字符 \w,另一个不是。
  • 在字符串末尾,如果最后一个字符是单词字符 \w
js 复制代码
let str = "hello, world!"
console.log(str.match(/\bhello\b/)); // [ 'hello', index: 0, input: 'hello, world!', groups: undefined ]
console.log(str.match(/\bworld\b/)); // [ 'world', index: 7, input: 'hello, world!', groups: undefined ]
console.log(str.match(/\bhell\b/)); // null 
console.log(str.match(/\bworld!\b/)); // null 
console.log("12 34 56".match(/\b\d\d\b/g)); // [ '12', '34', '56' ]

转义,特殊字符

  • 要将特殊字符转化为常规字符,需在其前面加反斜杠
  • 常用的特殊字符有:[] {} () \ ^ $ . | ? * +
js 复制代码
let str = "[注] 章节5.1部分有?的内容+"
console.log(str.match(/\d\.\d/)); //[ '5.1', index: 6, input: '[注] 章节5.1部分有?的内容+', groups: undefined ]
console.log(str.match(/\?/)); //[ '?', index: 12, input: '[注] 章节5.1部分有?的内容+', groups: undefined ]
console.log(str.match(/\[\W+\]/)); //[ '[注]', index: 0, input: '[注] 章节5.1部分有?的内容+', groups: undefined ]

集合和范围

  • 集合: [abc]表示3个字符中的任何一个:'a'、'b'、'c'; 虽然集合有多个字符,但它们在匹配中只会对应其中一个
  • 范围: [a-z]表示从'a'到'z'范围内的字符; [0-9A-Z]两个范围,字符要么0-9范围内的数字,要么A-Z范围内的字母。
  • 排除范围: [^...]通过在开头添加插入符号,来表示匹配所有除了给定字符之外的任意字符。
  • [...]的转义: 插入符号^仅在开头会被转义(表示排除),右方括号]总是会被转义; 除了在方括号中有特殊含义的字符外,其它所有特殊字符都是允许不转义的。
js 复制代码
let str = 'map, Tap, nap'
// 范围
let regexp = /[tm]ap/gi
console.log(str.match(regexp)); // [ 'map', 'Tap' ]
// 集合
let regexp1 = /[a-n]ap/gi
console.log(str.match(regexp1)); // [ 'map', 'nap' ]
// 排除范围
let regexp2 = /[^a-n]ap/gi
console.log(str.match(regexp2)); // [ 'Tap' ]
// [...]中的转义
let str1 = '1+2-[4*5]/(6.2-1)'
let regexp3 = /[-().^+*/[]]/g;
console.log(str1.match(regexp3)); // null 
let regexp4 = /[^-().+*/[]]/g
console.log(str1.match(regexp4)); // [ '5]' ]
let regexp5 = /[^-().+*/[\]]/g
console.log(str1.match(regexp5)); // ['1', '2', '4','5', '6', '2','1']

量词

示例 说明
{5} 匹配5个
{3,5} 匹配3-5个
{3,} 匹配3个及以上
+ 代表"一个或多个",同{1,}
* 代表"零个或多个",同{0,}
? 代表"零个或一个",同{0,1}
js 复制代码
let str = "please select from 12345 12 1234 123456 97 987 9887 98887 to finish this task."
let regexp = /\d{5}/
console.log(str.match(regexp)); // 12345
let regexp1 = /\d{3,4}/
console.log(str.match(regexp1)); // 1234 
let regexp2 = /\d{6,}/
console.log(str.match(regexp2)); // 123456
let regexp3 = /\d+/g
console.log(str.match(regexp3)); // [ '12345', '12', '1234', '123456' ]
let regexp4 = /9\d?7/g
console.log(str.match(regexp4)); // [ '97', '987' ]
let regexp5 = /9\d+7/g
console.log(str.match(regexp5)); // [ '987', '9887', '98887' ]
let regexp6 = /9\d*7/g
console.log(str.match(regexp6)); // [ '97', '987', '9887', '98887' ]

贪婪量词和惰性量词

js 复制代码
let str = 'Who can tell "impel" from "compel"'
// 在贪婪模式下(默认情况),两次都会尽可能多地重复
let regexp = /".+"/g
console.log(str.match(regexp)); // [ '"impel" from "compel"' ]
// 惰性模式,表示重复最少的次数;通过在量词后面添加'?'来实现,变成'*?'或'+?'或'??'
let regexp1 = /".+?"/g
console.log(str.match(regexp1)); // [ '"impel"', '"compel"' ]
// 换一种非惰性提取单词的方式
let regexp2 = /"[^"]+"/g
console.log(str.match(regexp2)); // [ '"impel"', '"compel"' ]

捕获组

模式的一部分可以用括号括起来(...),这被称为"捕获组" 这有两个影响:

  • 它允许将匹配的一部分作为结果数组中的单独项
  • 如果我们将量词放在括号后,则它将括号视为一个整体
js 复制代码
let str = "Gogogo right now! Google goose"
// 匹配重复括号内内容
let regexp = /(go)+/gi
console.log(str.match(regexp)); // [ 'Gogogo', 'Go', 'go' ]
let str1 = "cn.bing.com www.baidu.com my@mail.com work@edu.com"
// 匹配域名
let regexp1 = /(\w+\.)+\w+/g
console.log(str1.match(regexp1)); // [ 'cn.bing.com', 'www.baidu.com', 'mail.com', 'edu.com' ]
// 电子邮件 
let regexp2 = /[-.\w]+@([\w-]+\.)+[\w-]+/g
console.log(str1.match(regexp2)); // [ 'my@mail.com', 'work@edu.com' ]
let str2 = `<span class="desc"></span>`
// 嵌套组
let regexp3 = /<(([a-z]+)\s*([^>]*))>/
console.log(str2.match(regexp3)); // ['<span class="desc">','span class="desc"','span','class="desc"',index: 0, input: '<span class="desc"></span>', groups: undefined]
// 可选组 
console.log('a'.match(/a(b)?(c)?/)); // [ 'a', undefined, undefined, index: 0, input: 'a', groups: undefined ]
console.log('ac'.match(/a(b)?(c)?/)); // [ 'ac', undefined, 'c', index: 0, input: 'ac', groups: undefined ]
// 带有组搜索所有匹配项:matchAll
/**
 * 它返回的不是数组,而是一个可迭代对象
 * 当存在修饰符g时,它将每个匹配项以包含组的数组的形式返回
 * 如果没有匹配项,则返回的不是null,而是一个空的可迭代对象
 */
let str3 = '<h1> <h2>'
console.log(Array.from(str3.matchAll(/<(.*?)>/gi)));
// [
//   ['<h1>', 'h1', index: 0, input: '<h1> <h2>', groups: undefined],
//   ['<h2>', 'h2', index: 5, input: '<h1> <h2>', groups: undefined]
// ]
// 命名组
let regexp4 = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
let str4 = "2019-04-30";
console.log(str4.match(regexp4));
// [
//   '2019-04-30',
//   '2019',
//   '04',
//   '30',
//   index: 0,
//   input: '2019-04-30',
//   groups: [Object: null prototype] {
//     year: '2019',
//     month: '04',
//     day: '30'
//   }
// ]
// 替换中的捕获组
let str5 = 'John Bull'
let regexp5 = /(\w+) (\w+)/
console.log(str5.replace(regexp1, '$2,$1')); // Bull,John
// 非捕获组
let str6 = "Gogogo John!"
let regexp6 = /(?:go)+ (\w+)/i
console.log(str6.match(regexp6)); // ['Gogogo John','John',index: 0, input: 'Gogogo John!', groups: undefined]

选择 (OR) |

js 复制代码
let str = "First HTML appeared, then CSS, then JavaScript"
let regexp = /html|css|java(script)?|vue/gi
console.log(str.match(regexp)); // [ 'HTML', 'CSS', 'JavaScript' ]

前瞻断言与后瞻断言

  • 前瞻断言: x(?=y) 它表示"仅在后面是y时匹配x"。'x'和'y'可以是任何模式
  • 否定的前瞻断言: x(?!y) 它表示搜索x,但前提是后面没有y
  • 后瞻断言: (?<=y)x 它表示匹配x,仅在前面是y的情况下
  • 否定的后瞻断言: (?<!y)x 它表示匹配x,仅在前面不是y的情况下
  • 捕获组: 一般来说断言的内容不会成为结果的一部分,在某些情况下,我们可能还想捕获前瞻断言和后瞻断言所匹配的内容,或者部分内容,只需要将该部分包装在额外的括号中。
js 复制代码
let str = `1 turkey costs 30€`
// 前瞻断言
console.log(str.match(/\d+(?=€)/)); //[ '30', index: 15, input: '1 turkey costs 30€', groups: undefined ]
// 否定前瞻断言
console.log(str.match(/\d+(?!€)/)); //[ '1', index: 0, input: '1 turkey costs 30€', groups: undefined ]
let str1 = `2 turkey costs $30`
// 后瞻断言
console.log(str1.match(/(?<=\$)\d+/)); //[ '30', index: 16, input: '2 turkey costs $30', groups: undefined ]
// 否定后瞻断言
console.log(str1.match(/(?<!\$)\b\d+/g)); // [ '2' ]
// 捕获组
let regexp = /(?<=(\$|£))\d+/
console.log(str1.match(regexp));
// [
//   '30',
//   '$',
//   index: 16,
//   input: '2 turkey costs $30',
//   groups: undefined
// ]

Unicode 属性 \p{...}

  • 字母(Letter)L

    • 小写(lowercase)Ll
    • 修饰(modifier)Lm
    • 首字母大写(titlecase)Lt
    • 大写(uppercase)Lu
    • 其它(other)Lo
  • 数字(Number)N

    • 十进制数字(decimal digit)Nd
    • 字母数字(letter number)Nl
    • 其它(other)No
  • 标点符号(Punctuation)P

    • 连接符(connector)Pc
    • 横杠(dash)Pd
    • 起始引号(initial quote)Pi
    • 结束引号(final quote)Pf
    • 开(open)Ps
    • 闭(close)Pe
    • 其它(other)Po
  • 标记(Mark)M(accents etc):

    • 间隔合并(spacing combining)Mc
    • 封闭(enclosing)Me
    • 非间隔(non-spacing)Mn
  • 符号(Symbol)S

    • 货币(currency)Sc
    • 修饰(modifier)Sk
    • 数学(math)Sm
    • 其它(other)So
  • 分隔符(Separator)Z

    • 行(line)Zl
    • 段落(paragraph)Zp
    • 空格(space)Zs
  • 其它(Other)C

    • 控制符(control)Cc
    • 格式(format)Cf
    • 未分配(not assigned)Cn
    • 私有(private use)Co
    • 代理伪字符(surrogate)Cs
js 复制代码
// 需要使用 "u" 修饰符进行正则匹配
// 十六进制匹配 
let regexp1 = /x\p{Hex_Digit}\p{Hex_Digit}/u
console.log("number:xAf".match(regexp1)); // [ 'xAf', index: 7, input: 'number:xAf', groups: undefined ]

// 中文字符
let regexp2 = /\p{sc=Han}/gu
console.log("Hello Привет 你好 123_456".match(regexp2)); // [ '你', '好' ]

// 货币
let regexp3 = /\p{Sc}\d/gu
console.log('Prices:$2,€1, ¥9'.match(regexp3)); // [ '$2', '€1', '¥9' ]

结尾

好了,到这里常用的规则已经复习差不多了,阿呆用两个例子草草收尾吧,如果大佬有幸阅到,还请留下您美好的建议!!!

js 复制代码
let str = `<div class="out"><p class="inner"><span class="text"></span></p></div><div id="out"><p style="color:red;"><span style="position:absolute"></span></p></div>`
let regexp = /\s*(class|id|style)=("[a-z]+:?[a-z]+;?")/g
console.log(str.replaceAll(regexp, '')); // <div><p><span></span></p></div><div><p><span></span></p></div>

let str1 = "or Or oR OR Ordinary doctor sorry"
let regexp1 = /\bor\s+/gi
console.log(str1.replaceAll(regexp1, ' OR ')); //  OR  OR  OR  OR Ordinary doctor sorry
相关推荐
吾爱星辰8 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
前端李易安2 天前
正则表达式应用场景与常用正则验证方法汇总
正则表达式
HoneyMoose2 天前
正则表达式匹配英文字符
正则表达式
人生の三重奏2 天前
正则表达式(补充)
正则表达式
沟沟里的农民3 天前
【正则表达式】粗浅学习
正则表达式
一路向北_.3 天前
CTFshow 命令执行 web29~web36(正则匹配绕过)
web安全·正则表达式·ctfshow
神的孩子都在歌唱5 天前
正则表达式中的贪婪模式和非贪婪模式
数据库·mysql·正则表达式
Amo Xiang5 天前
2024 Python3.10 系统入门+进阶(十六):正则表达式
开发语言·python·正则表达式
激动的兔子5 天前
正则表达式的使用示例--Everything文件检索批量重命名工具
正则表达式·everything
学习使我快乐015 天前
Web APIs 6:正则表达式
前端·javascript·正则表达式