跳到主要内容

正则表达式入门

· 12 分钟阅读

在需要使用正则时搜一搜,复制粘贴改一改。有些时候看不太懂,只要能够跑的通就满意了,心里没有底,到底正不正确。又需要临时抱佛脚,并没有系统的去学习。学过之后过一段时间,就会忘记,反反复复,因此记录下来。

美国一位知名程序员杰米·加文斯基(Jamie Zawinski)说过一句话:

如果你有一个问题,你想到可以用正则来解决,那么你有两个问题了。

正则很难掌握和利用的工具。

既然这么难,使用的时候搜索以下,就解决问题了。为什么还要学习呢?

如果不熟悉一个技能的时候,遇见问题也想不到可以使用这个技术,根本就不会考虑这个技术。

什么是正则表达式

维基百科中的解释:

正则表达式(英语:Regular Expression,常简写为regex、regexp或RE),又称正则表示式正则表示法规则表达式常规表示法,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。

简单来说正则就是用来匹配处理文本字符串

为什么要使用正则表达式

工作时经常用到正则表达式,例如文件格式匹配

如何学习正则表达式?

每次学习都去搜索一下,搞定就结束,日积月累,可能会浪费更多的时间。容易忘记。

每天学习一个小时,坚持一周,学习的时间反而更短,还不容易忘记。

需求拆解

拿到需求后,这个需求可以拆分几个子需求。每个子需求是否独立。

例如网址:

什么是URL

"protocol + domain name + port + path to the file + parameters + anchor"

邮箱:

username + @ + domain name

这也是我们日常软件工程最基本的思路

分析各个子需求

每个子需求可能多个字符(字符组),多个字符串(分支),出现的次数(量词)。

语言规则

查阅语法手册、按照对应语言规则写下来就可以了。

TDD

使用TDD验证表达式是否正确。一次不一定写正确,从最简单的入手。

红色表示测试失败。

绿色表示测试通过。

测试通过后可以进行重构。并再次确保测试通过。

如何使用正则表达式?

保持克制。

一次性解决所有的问题,但是大家都看不懂 。 就没有可维护性。基本上只能够重写

  1. 能够使用字符串处理的,使用字符串。

  2. 一定要写注释

  3. 能使用多个简单的正则表达式解决的,一定不要苛求多个正则表达式。

字符

匹配文本

"I love JavaScript!".match(/love/);

匹配多个结果

多大多数正则表达式引擎默认情况下只返回第一个匹配结果。

在JavaScript中使用g(global,全局)标志将返回所有匹配的结果数组。

"I love love love JavaScript!".match(/love/g)

匹配不区分字母大小写

默认的情况下,正则表达式是区分大小的。JavaScript使用i标志强制执行不区分字母大小写

"I love Love love JavaScript!".match(/love/gi)

匹配任意字符

.可以匹配任意单个字符、字母、数字。

如果要匹配真正的点,需要转义\.

"Z".match(/./); // [ 'Z', index: 0, input: 'Z', groups: undefined ]

匹配特殊字符

点(.)在正则中有特殊含义的。如果真的需要匹配点,那么就需要使用反斜杠(\ )进行转义。

"test.js".match(/\.js/)

一组字符

匹配一组字符

[] 不匹配任何字符,只负责定义一个字符集合。字符集合是或(OR)不是和(AND)的关系

[0123456789] 任何数字

"Mop top".match(/[tm]op/gi);

字符区间

指定一组必须匹配其中之一的字符。

正则表达式频繁利用一些字符区间(0~9, a-z)等等,为了简化,使用- 连字符来定义字符区间。

  1. - 只有在[]中才是元字符。字符集合以外是普通的字符-
  2. 尾字符一定要大于首字符(例如[9-1]无效)

[A-Z] 匹配所有的大写字母

[a-z]匹配所有的小写字母

[0-9] 匹配任何数字

[A-Za-z0-9] 匹配字母与数字

[0-9A-Fa-f] 十六进制颜色

"test a string range".match(/[a-z]/g)

排除

排除字符集合里指定的哪些字符。

使用^符号。

[^0-9]: 匹配不是数字的字符

"No numbers here?".match(/[^0-9]/g)

元字符

有特殊含义,代表的不是字符本身。

匹配空白元字符

一般是根据操作系统不同,会用到的换行回车\r\n

元字符说明
[\b]回退(并删除)一个字符(Backspace键)
\f换页符
\n换行符
\r回车符
\t制表符
\v垂直制表符

匹配空白字符

元字符说明
\s=[\f\n\r\t\v]任何一个空白字符
\S=[^\f\n\r\t\v]任何一个非空白字符

\s来自space

包含空格、制表符\t\v\n\f\r不包含回退

\s不包含[\b]\S也没有排除[\b]

匹配数字

\d来自digit

元字符说明
\d = [0-9]任何一个数字字符
\D = [^0-9]任何一个非数字字符
"123-123123-12312".match(/\d/g) // 数字
"123-123123-12312".match(/\D/g) // 非数字

匹配字母数字下划线

元字符说明
\w = [a-zA-Z0-9_]任何一个字母数字或下划线字符_
\W = [^a-zA-Z0-9_]任何非一个字母数字或下划线字符_

\w 来自word

进制数值

\x 十六进制 \x0A即字符 10

\0 八进制\011 即字符9

重复匹配

匹配一个或多个字符

+ = {1,}

"123-123123-12312".match(/\d+/g) //  [ '123', '123123', '12312' ]
"123-123123-12312".match(/\D+/g) // [ '-', '-' ]

匹配零个或多个字符

*= {0,1}

"100 10 1".match(/\d0*/g); // 100 10 1
"100 10 1".match(/\d0+/g); // 100 10

匹配零个或一个字符

? = {0, 1}

符号可选,有点像可选操作符?

"Should I write color or colour?".match(/colou?r/g); //  [ 'color', 'colour' ]

匹配具体得重复次数

\d{5} 表示5位数字。只能匹配到5位数字,如果第六位还是数字是匹配不到的。

"test 12345 test".match(/\d{5}/g); // 12345

匹配区间范围

{m, n}

\d{2,4} 匹配2到4次

"Today is 5 22, 2022".match(/\d{2,4}/g); // 22 2022

匹配至少重复次数

{n,}

至少匹配4次。

"Today is 5 22, 2022".match(/\d{4,}/g); // 2022

懒惰性量匹配

*?

+?

{n,}?

描点

^ 表示字符串开始

$表示字符串结束

位置匹配

单词边界

使用\b 表示,也就是单词与空格间的位置

正则表达式的匹配有两种概念,一种匹配字符,一种匹配位置。 \b就是匹配位置。

\b\lucas\b

lucas lucas1 lucaslz

\B 不是单词边界(有空格就是单词边界就匹配不上了)。

lucaslucas1lucaslz

字符串边界

多行模式

JavaScript使用/m标志符表示多行模式

子表达式

用来定义字符或者表达式的集合。

() 定义一个子表达式

子表达式进行分组

( ){2,}

子表达式嵌套

或操作符

使用|表示,相当于条件选择。

(19|20) 能够匹配19902021中的19和21

反向引用

表达式在正则表达式内部被引用就称为反向引用。

可以把反向引用理解为变量

反向引用匹配

[ ]+(\w)[ ]+\1

This is a test test

替换操作

JavaScript在替换中使用$

const p = 'hello test@lucaslz.com';
const regex = /\w+[\w\.]*@[\w\,]+\.\w+)/;
p.replace(regex, '<a href="mailto:$1">$1</a>')

// result
hello <a href="mailto:test@lucaslz.com">test@lucaslz.com</a>

大小写转换

\E 结束\L或\U转换

\l 把下一个字符转换小写

\L 把\L到LE之间的字串全部转换为小写

\u把下一个字符转换大写

\U把\U到LE之间的字串全部转换为大写

环视

有些时候需要前后字符确定文本匹配的位置,但是又不希望出现在最终结果里面。

向前环视

(?=)

否定向前环视

(?!)

向后环视

(?<=)

否定向后环视

(?<!)

转义

元字符表示特殊含义的字符,所以这些字符就无法表示他们本身,因此需要转义。

使用反斜杠字符 \ 进行转义。

因此\ 也是元字符,所以也需要通过自己转义自己才能表示本身 \\

量词

限定前面这个字符允许出现的个数

贪婪型量词

匹配尽可能多的字符,多多益善。

懒惰性量词

匹配尽可能少的字符

注意事项

正则表达式区分字母大小写

例如\d\D

资源

https://regex101.com/

https://www.regextester.com/

多种语言校验正则表达式是否正确