当前位置:网站首页>这么多年了,还搞不懂正则语法?
这么多年了,还搞不懂正则语法?
2022-07-29 13:18:00 【小东同学】
不得不说,正则表达式的可读性却是比较差,但是作为开发人员,掌握正则表达式能够高效解决某些匹配问题,因此非常有必要学习正则表达式的语法及用途,本文将以一个实例带领大家轻松记忆正则语法!
懵逼正则
此文是翻译的正则表达式基础学习的文章,萌新手打翻译
0x00 正则表达式简介
作为一名程序猿,相信你可能已经在程序中看到过正则表达式,你可能会对于类似下面的字符串感到非常困惑。
/^\w+([\.-]?\w)[email protected]\w+([\.]?\w)+(\.[a-zA-Z]{2,3})+$/
此时,你可能已经在试图揣测这串儿正则表达式的意思...
正则表达式(Regex或RegExp)在加速算法游戏中十分有用,利用正则表达式,我们能够解决很多问题。初次看到正则表达式的语法结构可能会被吓到,但非常值得你掌握并在工作中正确使用正则表达式。
0x01 什么是Regex?很重要?
Regex(正则表达式)是一种通过“匹配”方式用于帮助你从任意字符串数据中提取有效信息的对象。无论是数字、字母、标点符号或者空格,Regex可以让你检查并匹配字符串中的任意字符组合。
例如,假设你现在需要从文本中获取社会保险号码或者是电子邮箱地址。那么,你可以使用Regex来检查被检索文本中是否存在相关信息,并且你还可以利用Regex替换他们,或者用于验证另一个截取的子字符串。把Regex当作是你的搜索栏——你可以根据需求约定你的的搜索规则,然后Regex会帮您搜索所需要的信息。
0x02 正则表达式的两种创建方式
1.正则字面量:
若要创建正则字面量,你只需要使用两个 \(反斜线) 来包裹Regex Pattern。
const regexLiteral = /helloworld/;
语法:/pattern/flags
2.正则表达式构造函数:
使用正则表达式构造函数将为你生成一个正则表达式
const greeting = 'hello';
const regexConstr = new RegExp(greeting);
语法:new RegExp(pattern[, flags])
**使用经验:**如果你的正则表达式是一个不变的常量,那么使用正则字面量将会有更好的性能。但如果该正则表达式经常改变,则最好使用正则表达式构造函数来动态生成。
0x03 正则表达式的使用
test()、match()和 replace() 是三种常用的正则使用方法,因此你应当熟练使用它们。
3.1 RegExp.prototype.test()
.test() 方法会返回一个布尔值——被检索的字符串中是否存在符合pattern的信息
const str1 = "i love regex";
const str2 = "it is cool";
const hasRegex = /regex/;
hasRegex.test(str1);
// expected output: true
hasRegex.test(str2);
// expected output: false
3.2 String.prototype.match()
可以使用 .match() 方法来代替 只返回是否匹配布尔值的.test() 方法。.match() 方法可以返回在当前字符串中所有满足匹配条件的结果数组。尽管使用 .test() 方法来判断是否存在符合条件的信息的确很方便,但有时候,我们也会试控制在整个搜索匹配的过程。
这种情况下,.match()方法就派上了用场,根据你正则规则返回符合条件的结果数组,如下是一个基本使用案例。然后,你会看到当我们同时使用标志符时,.match() 将会是一个给力的方法。
const str = "I love JavaScript";
const result = str.match(/JavaScript/);
console.log(result)
// expected output: ['JavaScript']
3.3 String.prototype.replace()
.replace() 方法会在字符串中搜索一个指定的值(或者指定的正则表达式),然后会返回一个被替换了指定值的新字符串。
const sentence = 'I love dogs more than cats.';
const regex = /dogs/;
console.log(sentence.replace(regex, 'bunnies'));
// expected output: "I love bunnies more than cats."
**注意:**当使用指定值时,字符串中如果存在多个指定的值,但仅会替换第一个匹配到的值,如果想要替换多个,那么可以指定正则表达式。
const str = "Hello World World!";
const replacement = str.replace("World", "Planet");
console.log(replacement)
// expected output: “Hello Planet World!”
0x04 中括号表达式
在中括号表达式中,你可以设置用于指定需要匹配的任意字符或字符集合。
例如,const regex=/[A-Z]/。如此,将搜索匹配字母表中所有的大写字母。
[a-z] 匹配字母表中所有小写字母
[A-Z] 匹配字母表中所有大写字母
[abcd] 在字符串中匹配小写字母a、b、c或d
[a-d] 同上,即可指定每个值,也可以使用“短横线”连接的字符集合
[a-gA-C0-7] 匹配字符串中的小写字母a~g集合,大写字母A~C集合或数字0~7集合中的任意字符
[^a-zA-Z] 匹配字符串中非英文大小写字母的字符 (在指定字符集合中,使^字符,意味着匹配指定字符集的补集)
0x05 标志
在正则表达式的反斜杠后,我们可以指定一个标志或者标志的组合。正则表达式借助标志(flags)作为如何正确检索和匹配pattern中自定义字符的标准。
const sentence = 'The Cat in the Hat is not a cat.'
const regex = /[A-Z]/;
const found = sentence.match(regex);
console.log(found);
// expected output: ['T']
“标志”是一个非必须指定的内容。没有指定标志,正则表达式会匹配第一个符合规则(pattern)返回true的字符。在如上的例子中,我们的程序会返回 ['T'],因为在句子中找到了第一个大写字母T。
g:global(全局),其作用是将字符串中满足表达式的所有结果均返回。换句话说,不仅仅返回满足条件的第一项,而是返回所有存在的匹配项。参考上面的例子,现在我们把g标志添加到反斜杠的后边,就像这样,const regex = /A-Z/g,然后,上面的match()方法将返回所有满足pattern(大写字母)的字符数组。因此,先检查sentence,“The Cat in the Hat is not a cat.”,然后会返回三个大写字母的数组['T', 'C', 'H']i:insensitive(不敏感),其作用是大小写不敏感。例如,const regex = /[TheCatInTheHat]/ig可以同时使用global和insensitive,这个表达式将会返回上面sentence中的每一个字符在返回的数组中['T', 'h', 'e', 'C', 'a', 't', 'i', 'n', 't', 'h', 'e', 'H', 'a', 't', 'i', 'n', 't', 'a', 'c', 'a', 't']- m:multi-line(多行),其作用是配合^和标志作为匹配的起点和终点,而不是整个字符串(原作者列举的例子不太好说明区别)。我的理解是,m标志用于指定多行输入的字符串应该被当作多个行。如果使用了m标志,则会根据 ^ 和 来确定字符串开始匹配和结束匹配的区间,没有的话,就默认是整个字符串(如果没有 ^ 或
const sentence = '123\n456\nabc\nDEF\naa1';
sentence.match(/\d$/) // 匹配字符串末尾是数字的情况
sentence.match(/\d$/m) // 多行的情况下匹配第一个满足行末尾是数字的情况
sentence.match(/\d$/g) // 加上全局标志,返回所有末尾是数字的数组
sentence.match(/\d$/gm)// 再加上多行标志,则会比较每一行
示例
另外作为补充,当需要多个字符集进行匹配的时候,还有另外三个标志可以提供帮助
const sentence = 'There are 350 dogs and 17 cats in the house.'
const regex = /\d/
const found = sentence.match(regex);
console.log(found);
// expected output: ['3']
d:\d匹配数字类型字符,与[0-9]相同,因此在上面例子中将返回第一个匹配的数字,返回结果为['3']w:\w匹配任意的字母数字和下划线,与[0-9a-zA-Z_]相同s:\s匹配空白类型字符,如果将例子中改为const regex = /\w\s/,那么返回的结果就是['e'],是There空格匹配返回的结果,空白字符有\n,空格,\t,
\d、\w和\s的补集是\D、\W、\S
- \D匹配所有非数字(等同于
[^0-9]) - \W匹配所有非数字字母和下划线字符(等同于
[^0-9a-zA-Z_]) - \S匹配所有非空白的字符(等同于
[^\s])
0x06 量词
量词(quantifiers)是正则表达式中的基本符号,具有特殊意义
- * 前一字符的匹配数量为0或更多
- + 前一字符的匹配数量为1或更多
- ? 前一字符的匹配数量为0或1个;前一个字符(item,项)可有可无
- ^ 字符串的起始符号
- $ 字符串的结尾符号
- . 匹配任意字符,换行符除外
- {m, n}: m是0或一个正整数,表明了至少匹配的数目, n是一个大于或等于m的正整数,表明了至多匹配数目
接下来,通过下面这个例子来看看我们所理解的Regex。
const str = 'for__if__rof__fi'
const regex = /[a-z]+/g;
console.log(found);
显而易见,正则表达式会去匹配所有的小写字母的字符,并且使用了+符号来修饰前一个规则,以匹配所有满足前一个规则的所有字符,上面的代码将打印输出:['for', 'if', 'rof', 'fi']。
再看看,如果正则表达式中没有符号+的结果会是怎样
const regex = /[a-z]/g;
那么返回值将会是:['f','o','r','i','f','r','o','f','f','i'].
0x07 灵活运用
还记得我们在文章一开始就提到的那一串难以理解的字符串吗?
/^\w+([\.-]?\w)[email protected]\w+([\.]?\w)+(\.[a-zA-Z]{2,3})+$/
这是一个常用于邮件格式化的正则表达式,现在我们已经学会了Regex的基本用法和术语,下面我们来一步步拆分理解一下这个正则表达式
const email = '[email protected]’
const regex = /^\w+([\.-]?\w)[email protected]\w+([\.]?\w)+(\.[a-zA-Z]{2,3})+$/
const found = regex.test(email);
console.log(found);
// expected output: true
- 1.首先,我们一部份一部份地去理解这个表达式。在字符串的开始是一个
^\w+。^符号表明从字符串的开头开始匹配,然后\w会匹配所有的字母、数字和下划线,符号+表明至少有一个满足前一规则。在例子,这第一部分的规则会从email中匹配到student - 2.然后,第二部分的规则是
([\.-]?\w)+。一对括号包裹起来作为第一个捕获组,在括号里有一个字符集,该字符集将匹配.或-,而?表明前一个字符有无.或-都可以,是可选的。然后是\w,只会匹配一个字母、数字或下划线字符。外边的+表明前面的组合规则在字符串中至少有一项满足。所以第二部分规则,将返回-id。如果email是有两个连接符的student — [email protected],那么会被认为是一个不合法的邮箱 - 3.第三部分是
@\w+,会检查有一个符号@,并且其后w+表明有一个或多个字母、数字,将会匹配例子中的@alumni。 - 4.接下来是
([\.]?\w)+,这部分和第二部分的规则类似,它只会检查点号的有无,这将会匹配到.school - 5.下一部分是
(\.[a-zA-Z]{2,3})+,是检查邮件格式的重要部分。这部分将匹配邮箱地址中的顶级域名,会匹配到域名中的后缀,例如com、org或net。首先会寻找到一个.,然后是2~3个无论大小写的英文字母。在这个例子中,将匹配到.edu - 最后是一个
$符号,表明字符串结尾
这部分个人觉得作者说的有部分不符合规则,在第4步,该规则应该是会匹配到
.school.edu
运行结果
这就是Regex!现在我们已经知道如何使用正则来校验邮箱地址。此外,你可以在正则表达式中使用中括号,标志符,量词来完善我们正则中可能没考虑到的极端用例。
0x08 总结
对于开发人员来说,学会Regex的知识应该非常有用。如上所示,Regex最常用于需要安全校验的情况。当开发人员需要匹配URL或通过某些文本进行解析或提取某些信息(例如yyyy-mm-dd的日期格式)时,也可以用正则来实现该功能。正则表达式无处不在!
正则表达式看起来似乎非常难以理解,有的人并以此为不去学习Regx的理由。但没必要这样,学习正则表达式是一个难度渐增的过程,今天学习的基础知识就是一个起点
0x09 参考文章和资源
- Regex Cheatsheet
- Regular Expression Editor
- Regex Crossword Puzzle
- MDN Documentation for Regex 这个非常棒
- RegEx Golf
原文链接:《Understanding Regex 101》
翻译备注:在某需求驱使下看到此文,虽然有点基础,但是笔者为了练习翻译,与此同时也希望能够对学习正则语法的同学有所帮助。
0xFF 补充:常用的正则语法
符号 | usage | 说明 |
|---|---|---|
* | a* | 前一个元素0个或多个,贪婪 |
? | a? | 前一个元素0个或1个 |
+ | a+ | 前一个元素1个或多个 |
[] | [abc] | 前一个元素是a或b或c |
() | (abc) | 捕获“abc”,Capture everything enclosed |
\ | \n | 转义其后字符 |
^ | [^a-z] | 前一个字符不是a~z中任意一个字符 |
\n | Newline | |
\t | Tab | |
\0 | Null character | |
- | [a-z] | A character in the range a~z |
\s | Any whitespace character | |
\S | Any non-whitespace character | |
\d | Any digit | |
\D | Any noe-digit | |
\w | Any word character [0-9a-zA-Z] | |
\W | Any none-word character | |
(?:..) | Match everything enclosed, but won't capture | |
| | (a|b) | Match either a or b |
{} | a{1},a{2,},a{3,5} | Exactly 1 of a, 2 or more of a, between3 and 5 of a |
最后送大家一个键盘(复制后在Console运行):
(_=>[..."`1234567890-=~~QWERTYUIOP[]\\~ASDFGHJKL;'~~ZXCVBNM,./~"].map(x=>(o+=`/${b='_'.repeat(w=x<y?2:' 667699'[x=["Bs","Tab","Caps","Enter"][p++]||'Shift',p])}\\|`,m+=y+(x+' ').slice(0,w)+y+y,n+=y+b+y+y,l+=' __'+b)[73]&&(k.push(l,m,n,o),l='',m=n=o=y),m=n=o=y='|',p=l=k=[])&&k.join`
`边栏推荐
猜你喜欢
随机推荐
MySQL8.0学习记录21 - 视图
PAT 甲级 A1021 Deepest Root
程序员是职业病高发群体,别天真的以为只有秃头那么简单,才不是呢。
The core principles of electronic games
[WeChat applet] One article to solve button, input, image components
还在开发短信验证码登录?试试(本机号码一键登录)
The interviewer was stunned by the self-growth of 4 mainstream database IDs in one breath
Create and copy conda environment
Research on the thinking and application methods of the frontier of ESI research
HMS Core音频编辑服务音源分离与空间音频渲染,助力快速进入3D音频的世界
Leetcode66. 加一
基于对象的实时空间音频渲染丨Dev for Dev 专栏
Alibaba CTO Cheng Li: open source is the source of basic software!
Sqoop导入导出时数据内存溢出
手摸手写一个互联网黑话生成器
Dataset:Medical Data and Hospital Readmissions医疗数据和医院再入院情况数据集的简介、下载、使用方法之详细攻略
连接oracle数据库指令
项目经理:不错啊!SSO单点登录代码写出来了,把时序图也画一下?
轻松学Pytorch-Pytorch可视化
理解yolov7网络结构









