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

最近因为项目中有些地方需要正则,给我难受坏了,因为这东西看了就忘,用到就得查,属实难为人了,那今天菜鸟又粗略整理了一遍,以便之后用到翻看。文中有些例子和分类思路用到了网站中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
相关推荐
吴声子夜歌7 小时前
正则表达式——边界
正则表达式
营养充电站15 小时前
C++23 新特性在 CLion 中的实战体验
macos·docker·jupyter·正则表达式
吴声子夜歌1 天前
正则表达式——字符组
正则表达式
天若有情6731 天前
自制浏览器端文本批量处理小工具,支持查找替换、内容删除、正则表达式,开箱即用
正则表达式
吴声子夜歌1 天前
正则表达式——简单的模式匹配
正则表达式
吴声子夜歌2 天前
正则表达式——前后查找
正则表达式
吴声子夜歌2 天前
正则表达式参考
正则表达式
吴声子夜歌2 天前
正则表达式——常见应用软件和编程语言中的正则表达式
正则表达式
吴声子夜歌2 天前
正则表达式——使用子表达式
正则表达式
吴声子夜歌3 天前
正则表达式——重复匹配
正则表达式