从零开始学正则,正则就是这么简单

155 阅读9分钟

一、工具篇

1.1 正则图解神器 Regulex

Regulex 这个工具也是我在阅读正则表达式迷你书时,作者推荐的一个工具。长正则表达式由于包含多个分组,有时候我们单纯通过代码来理解整个表达式,可能会让人感到困惑,不知道每个部分的作用。但是通过图解工具,可以清晰地展示每个分组的作用,帮助我们更好地理解整个正则表达式的结构。

1.2 正则在线调试工具regexr

如果说 Regulex 和 regex-vis 主要用于帮助我们阅读正则表达式的结构,那么 Regexr 则非常方便地帮助我们在线编写正则表达式。在日常开发中,我们可能会编写一个正则表达式,看起来似乎满足了需求,但又担心它会匹配到我们不想要的内容。这时,regexr 就能发挥很好的测试作用。

regexr 的界面非常简单,分为三个区域:上方的 Expression 区域用于编写正则表达式,下方的 Text 区域用于输入测试用例,而最底部的工具栏 Tools 则提供了更多功能,让你可以更轻松地编写和测试正则表达式。

image.png 比如在上图中,我定义了一个正则 /\d+/,以及一个例子 123abc12 ,于是被匹配的区域成功高亮。

1.3 vscode 插件 Regex Previewer

除了在线网站,有时候我们在编写代码时也希望立即测试正则表达式是否有效,这时可以使用 Regex Previewer 这个插件。安装后,在代码中所有包含正则表达式的地方会出现一个 test 按钮,点击后会在新的标签页中显示一些测试用例,并且匹配的内容会被高亮显示。需要注意的是,目前该插件不支持使用正则表达式构造器的写法。

常见正则api速查

二、正则的学习开始

2.1 创建语法

  • 方法一:字面量方式 语法格式为: /正则表达式主体/修饰符(可选)
    const reg = /\d/gi;
  • 方法二:构造函数 语法格式为:new RegExp(正则表达式主体[, 修饰符])
    const reg = new RegExp('\d', 'gi')

常用修饰符如下

修饰符作用
i忽略大小写匹配
g全局匹配,即是匹配一个后继续匹配,直到结束
m多行匹配,即是遇到换行后不停止匹配,直到结束

2.2 常用语法学习

2.2.1 匹配任意字符(.

这个就很简单,相当于匹配任意所有的字符 image.png

2.2.2 匹配开始和结束位置(^$

  • ^ 匹配输入的开始。如果多行标志被设置为 true,那么也匹配换行符后紧跟的位置。

    • 例如,/^A/ 并不会匹配 an A 中的 A,但是会匹配 An E 中的 A
  • $ 匹配输入的结束。如果多行标志被设置为 true,那么也匹配换行符前的位置。

    • 例如,/t$/ 并不会匹配 eater 中的 t,但是会匹配 eat 中的 t

2.2.3 匹配数字和字母(w 和 W)

  • \w 匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_]

    • 例如,/\w/ 匹配 apple, 中的 a$5.28,中的 53D. 中的 3
  • \w 匹配一个非单字字符。等价于 [^A-Za-z0-9_]

    • 例如,/\W/ 或者 /[^A-Za-z0-9_]/ 匹配 50%. 中的 %

2.2.4 匹配数字和空白字符(d 和 s)

  • \d 匹配一个数字。``等价于 [0-9]

    • 例如, /\d/ 或者 /[0-9]/ 匹配"B2 is the suite number."中的'2'。
  • \D 匹配一个非数字字符。``等价于 [^0-9]

    • 例如, /\D/ 或者 /[^0-9]/ 匹配B2 is the suite number.中的B
  • \s 匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[\f\n\r\t\v\u0020\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]

    • 例如,/\s\w*/ 匹配foo bar.中的 bar
  • \S 匹配一个非空白字符。等价于[^\f\n\r\t\v\u0020\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]

    • 例如,/\S\w*/ 匹配foo bar.中的foo

2.2.4 匹配字符集合( []

  • /[xyz]/ 一个字符集合。匹配方括号中的任意字符,包括转义序列。你可以使用破折号(-)来指定一个字符范围。对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。他们不必进行转义,不过转义也是起作用的。
    • 例如,[abcd][a-d] 是一样的。他们都匹配brisket中的b,也都匹配city中的c/[a-z.]+//[\w.]+/与字符串test.i.ng匹配。
  • /[^xyz]/ 一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。
    • 例如,[^abc][^a-c] 是一样的。他们匹配brisket中的r,也匹配chop中的h

2.2.5 匹配重复一次或多次( +

  • + 匹配前面一个表达式 1 次或者多次。等价于 {1,}
    • 例如,/a+/ 会匹配candy 中的 acaaaaaaandy 中所有的 a,但是在 cndy 中不会匹配任何内容。

2.2.6 匹配重复 0 次或多次( *

  • * 匹配前一个表达式 0 次或多次。等价于 {0,}
    • 例如,/bo*/ 会匹配 A ghost boooooed 中的 boooooA bird warbled 中的 b,但是在 A goat grunted 中不会匹配任何内容。

2.2.7 匹配重复 0 次或 1 次( ?

  • ? 匹配前面一个表达式 0 次或者 1 次。等价于 {0,1}
    • 例如,/e?le?/ 匹配 angel 中的 elangle 中的 le 以及 oslo 中的 l

2.2.8 分组匹配(()

  • (x) 它会匹配 'x' 并且记住匹配项。

    模式 /(foo) (bar) \1 \2/ 中的 '(foo)' 和 '(bar)' 匹配并记住字符串 "foo bar foo bar" 中前两个单词。模式中的 \1 和 \2 表示第一个和第二个被捕获括号匹配的子字符串,即 foo 和 bar,匹配了原字符串中的后两个单词。注意 \1\2、...、\n 是用在正则表达式的匹配环节,详情可以参阅后文的 \n 条目。而在正则表达式的替换环节,则要使用像 $1$2、...、$n 这样的语法,例如,'bar foo'.replace(/(...) (...)/, '$2 $1')$& 表示整个用于匹配的原字符串。

  • (?:x) 匹配 'x' 但是不记住匹配项。

    • 这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。看看这个例子 /(?:foo){1,2}/。如果表达式是 /foo{1,2}/{1,2} 将只应用于 'foo' 的最后一个字符 'o'。如果使用非捕获括号,则 {1,2} 会应用于整个 'foo' 单词

2.2.9 正向预查((?=)

  • x(?=y) 匹配x仅仅当x后面跟着y.这种叫做先行断言
    • 例如,/Jack(?=Sprat)/会匹配到Jack仅当它后面跟着Sprat/Jack(?=Sprat|Frost)/匹配Jack仅当它后面跟着Sprat或者是Frost。但是SpratFrost都不是匹配结果的一部分。

2.2.10 反向预查((?<=)

  • x(?<=y) 匹配x仅当x前面是y.这种叫做后行断言。
    • 例如,/(?<=Jack)Sprat/会匹配到Sprat仅仅当它前面是Jack/(?<=Jack|Tom)Sprat/匹配Sprat 仅仅当它前面是Jack或者是Tom。但是JackTom都不是匹配结果的一部分。

2.2.11 或(|

  • x|y 匹配x或者y
    • 例如,/green|red/匹配green apple中的greenred apple中的red

2.2.12 匹配前一个字符出现至少n次({n,m}

  • {n} n 是一个正整数,匹配了前面一个字符刚好出现了 n 次。

    • 例如,/a{2}/ 不会匹配candy中的a,但是会匹配caandy中所有的 a,以及caaandy中的前两个a
  • {n,} n 是一个正整数,匹配前一个字符至少出现了 n 次。

    • 例如,/a{2,}/ 匹配 aa, aaaaaaaaa 但是不匹配 a
  • {n,m} nm 都是整数。匹配前面的字符至少 n 次,最多 m 次。如果 n 或者 m 的值是 0,这个值被忽略。

    • 例如,/a{1, 3}/ 并不匹配cndy中的任意字符,匹配candy中的 a,匹配caandy中的前两个 a,也匹配caaaaaaandy中的前三个 a。注意,当匹配caaaaaaandy时,匹配的值是aaa,即使原始的字符串中有更多的 a

三、前端常用-正则表达式

在表单验证中,使用正则表达式来验证正确与否是一个很频繁的操作,本文收集整理了15个常用的javaScript正则表达式,其中包括用户名、密码强度、整数、数字、电子邮件地址(Email)、手机号码、身份证号、URL地址、 IPv4地址、 十六进制颜色、 日期、 QQ号码、 微信号、车牌号、中文正则。

3.1 用户名正则

//用户名正则,4到16位(字母,数字,下划线,减号)
var uPattern = /^[a-zA-Z0-9_-]{4,16}$/;
//输出 true
console.log(uPattern.test("caibaojian"));

3.2 密码强度正则

//密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
var pPattern = /^.*(?=.{6,})(?=.*d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;
//输出 true
console.log("=="+pPattern.test("caibaojian#"));

3.3 整数正则

//正整数正则
var posPattern = /^d+$/;
//负整数正则
var negPattern = /^-d+$/;
//整数正则
var intPattern = /^-?d+$/;
//输出 true
console.log(posPattern.test("42"));
//输出 true
console.log(negPattern.test("-42"));
//输出 true
console.log(intPattern.test("-42"));

3.4 数字正则

可以是整数也可以是浮点数

//正数正则
var posPattern = /^d*.?d+$/;
//负数正则
var negPattern = /^-d*.?d+$/;
//数字正则
var numPattern = /^-?d*.?d+$/;
console.log(posPattern.test("42.2"));
console.log(negPattern.test("-42.2"));
console.log(numPattern.test("-42.2"));

3.5 Email正则

//Email正则
var ePattern = /^([A-Za-z0-9_-.])+@([A-Za-z0-9_-.])+.([A-Za-z]{2,4})$/;
//输出 true
console.log(ePattern.test("99154507@qq.com"));

3.6 手机号码正则

//手机号正则
var mPattern = /^1[34578]d{9}$/; //http://caibaojian.com/regexp-example.html
//输出 true
console.log(mPattern.test("15507621888"));

3.7 身份证号正则

//身份证号(18位)正则
var cP = /^[1-9]d{5}(18|19|([23]d))d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)d{3}[0-9Xx]$/;
//输出 true
console.log(cP.test("11010519880605371X"));

3.8 URL正则

//URL正则
var urlP= /^((https?|ftp|file)://)?([da-z.-]+).([a-z.]{2,6})([/w .-]*)*/?$/;
//输出 true
console.log(urlP.test("http://caibaojian.com"));

3.9 IPv4地址正则

//ipv4地址正则
var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
//输出 true
console.log(ipP.test("115.28.47.26"));

3.10 十六进制颜色正则

//RGB Hex颜色正则
var cPattern = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;
//输出 true
console.log(cPattern.test("#b8b8b8"));

3.11 日期正则

//日期正则,简单判定,未做月份及日期的判定
var dP1 = /^d{4}(-)d{1,2}1d{1,2}$/;
//输出 true
console.log(dP1.test("2017-05-11"));
//输出 true
console.log(dP1.test("2017-15-11"));
//日期正则,复杂判定
var dP2 = /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/;
//输出 true
console.log(dP2.test("2017-02-11"));
//输出 false
console.log(dP2.test("2017-15-11"));
//输出 false
console.log(dP2.test("2017-02-29"));

3.12 QQ号码正则

//QQ号正则,5至11位
var qqPattern = /^[1-9][0-9]{4,10}$/;
//输出 true
console.log(qqPattern.test("65974040"));

3.13 微信号正则

//微信号正则,6至20位,以字母开头,字母,数字,减号,下划线
var wxPattern = /^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/;
//输出 true
console.log(wxPattern.test("caibaojian_com"));

3.14 车牌号正则

//车牌号正则
var cPattern = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/;
//输出 true
console.log(cPattern.test("粤B39006"));

3.15 包含中文正则

//包含中文正则
var cnPattern = /[u4E00-u9FA5]/;
//输出 true
console.log(cnPattern.test("蔡宝坚"));

四、在线练习正则-完成及掌握

regex101

image.png