正则表达式

421 阅读3分钟

应用场景

  • 表单验证里面,验证字符的合法性,如邮箱是否合法,手机号是否合法等等
  • 信息过滤,如论坛帖子或者评论中的非法字符,例如 sql注入、js脚本注入、煽动性的言论
  • 信息采集,采集别人网站上面的内容,例如整页采集时 筛选出需求的部分
  • 信息替换
  • 页面伪静态的规则

测试地址

修饰符

js 修饰符的用法,是修饰符一定要写到 // 之后,可以一次性使用多个修饰符 /^...$/igm

  • i 执行对大小写不敏感的匹配。实际上就是不区分大小写的匹配
  • g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
  • m 执行多行匹配

转义字符

如果匹配的字符串在正则中有特殊含义的都必须加转义字符。如[]$.*?+|^{}()

但是能要乱加转义

1. 量词

前导字符: 就是紧挨着(+*?)等的前一个字符

  • n+ 匹配任何包含至少一个 n 的字符串。匹配一个或多个前导字符
  • n* 匹配任何包含零个或多个 n 的字符串。前导字符有没有也可以
  • n? 匹配任何包含零个或一个 n 的字符串
  • n{X} 匹配包含 Xn 的序列的字符串
  • n{X,Y} 匹配包含 XYn 的序列的字符串,包括 XY
  • n{X,} 匹配包含至少 Xn 的序列的字符串
  • n$ 匹配任何结尾为 n 的字符串。从末尾开始匹配
  • ^n 匹配任何开头为 n 的字符串。(注意位置在前面)

    js is so cool, js, 如果使用 /^js/g (为 js 的匹配规则, g 表示全局匹配, 匹配规则放在 // 里面). 表示 匹配当前字符串的开头是不是js

  • ^n$ 表示只匹配字符串 n, 也就是匹配整个字符串

    /js$/g 匹配当前字符串的结尾是不是js

2. 懒惰限定符

  • *? 重复任意次,但尽可能少重复

    如 "acbacb" 正则 "a.*?b" 只会取到第一个"acb" 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符 ,而"acbacb"最少字符的结果就是"acb"

  • +?` 重复1次或更多次,但尽可能少重复

    与上面一样,只是至少要重复1次

  • ?? 重复0次或1次,但尽可能少重复

    如 "aaacb" 正则 "a.??b" 只会取到最后的三个字符"acb"

  • {n,m}? 重复n到m次,但尽可能少重复

    如 "aaaaaaaa" 正则 "a{0,m}" 因为最少是0次所以取到结果为空

  • {n,}? 重复n次以上,但尽可能少重复

    如 "aaaaaaa" 正则 "a{1,}" 最少是1次所以取到结果为 "a"

3. 元字符

  • . 表示单个字符,表示任意字符。除了换行和行结束符
  • * 表示任意字符串( 0 个或多个任意字符,除了换行和行结束符).也是任意一个字符,* 表示任意个前导字符。二者组合表示任意字符串
  • \w 匹配任何数字、字母、下划线。一个 \w 表示一个字符
  • \W 匹配任何非数字、非字母、非下划线。
  • \d 查找数字。
  • \D 查找非数字字符
  • \s 查找空白字符
  • \S 查找非空白字符
  • \b 匹配单词边界(边界字母个数没有限制;\b放前面表示匹配单词前面的边界,\b表示匹配单词后面的边界)
  • \B 匹配非单词边界
  • \n 查找换行符
  • \r 查找回车符
  • \t 查找制表符

4. 中括号/方括号/[]

方括号表示一个范围,也称为 字符簇

  • [abc] 查找方括号之内的任何字符。
  • [^abc] 查找任何不在方括号之间的字符。(方括号中的^表示取反)
  • [0-9] 查找任何从 09 的数字。表示一个字符
  • [a-z] 查找任何从小写 a 到小写 z 的字符。
  • [A-Z] 查找任何从大写 A 到大写 Z 的字符。
  • [A-z] 查找任何从大写 A 到小写 z 的字符。包括下划线。
  • [5-8] 查找 5 <= 目标 <= 8 的字符(red|blue|green) 查找任何指定的选项。(竖线|表示或者)

    /[0-9]|[a-z]/g 表示查找 0~9a~z 的字符

5. 分组/捕获和反向引用

正则中出现的小括号,就叫捕获或者分组

在正则语法中(在 /…/ 内),在捕获的后面,用 \1 来引用前面的捕获。用 \2 表示第二个捕获的内容…. 在正则语法外(如 replace 时),用 $1 来引用前面的捕获


var str1 = "1111 3213 4345 12341 2990 2323";
// 匹配连续4个数字
var result = str1.match(/\d{4}/g);  // [ '1111', '3213', '4345', '1234', '2323' ]
// 匹配连续4个数字, 第1个和第3个数字相同
var result1 = str1.match(/(\d)\d\1\d/g);  // [ '1111', '4345', '2323' ]
// 匹配连续4个数字, 第1个和第3个数字相同, 并且第2个和第4个数字相同 
var result2 = str1.match(/(\d)(\d)\1\2/g);  // [ '1111', '2323' ]
console.log(result2);

禁止引用

(?:正则) 这个小括号中的内容不能够被引用

var result3 = str1.match(/(?:\d)(\d)\1\2/g);  // 这样是 ❌的, 第一个括号内是不可以被引用的 所以\1只能引用第二个括号的内容, \2 也就无效了
console.log(result3);  // null

6. 环视(断言/零宽断言/正向预测/负向预测)

every(?=n) 匹配任何其后紧接指定字符串 n 的字符串。 有一个字符串是 abacad ,从里面查找 a ,什么样的 a 呢?后面必须紧接b的a。 正则语法是:/a(?=b)/g

var str1 = "abacad";
var result = str1.match(/a(?=b)/g);
console.log(result);  // [ 'a' ]

延伸一下,案例中的a、b都是正则表达式,实际上换一个复杂一点的正则表达式也是可以的

var str1 = "iOS12 PHP7 JS JAVA ";
var result = str1.match(/[A-Za-z]+(?=\d)/g);
console.log(result);  // [ 'iOS', 'PHP' ]

var str2 = "iOS12 PHP7 JS JAVA hello中国 ";
var result2 = str2.match(/[A-Za-z]+(?=\d|[\u4e00-\u9fa5])/g);
console.log(result2);  // [ 'iOS', 'PHP', 'hello' ]

every(?!n) 匹配任何其后没有紧接指定字符串 n 的字符串。 有一个字符串是abacad,从里面查找a,什么样的a呢?后面不能紧接ba

正则语法是:/a(?!b)/g

var str1 = "abacad";
var result = str1.match(/a(?!b)/g);
console.log(result);  // [ 'a', 'a' ]

另外,还会看到(?!B)[A-Z]这种写法,其实它是[A-Z]范围里,排除B的意思,前置的(?!B)只是对后面数据的一个限定,从而达到过滤匹配的效果

var str1 = "ABCDEFG";
var result = str1.match(/(?!B)[A-Z]/g);  // [ 'A', 'C', 'D', 'E', 'F', 'G' ]
var result2 = str1.match(/(?![B-D])[A-Z]/g);  // [ 'A', 'E', 'F', 'G' ]

var str1 = "423234d6345743";
// 从头匹配到尾, 必须是纯数字
var result = str1.match(/^\d+$/g);
console.log(result);  // null
var result1 = str1.match(/(?!^\d+$)^[A-Za-z0-9]+$/g);
console.log(result1);  // [ '423234d6345743' ] 如果是纯数字则为null