正则表达式从原理到实战全面学习小结

目录
  • 正则是啥?
  • 简单字符
  • 转义字符
  • 字符集和
  • 量词
  • 字符边界
  • 选择表达式
  • 分组与引用
  • 预搜索
  • 修饰符
  • 图形化工具
  • JavaScript中的正则
  • RegExp#test
  • RegExp#exec
  • String#search
  • String#match
  • String#split
  • String#replace
  • RegExp
  • 实例属性
  • 实战实例
  • 总结

正则表达式,名字听上去就没有吸引力,我发现很多前端对正则表达式了解不深,甚至有些惧怕,每次能够运行全凭运气,更有甚者完全靠复制粘贴。

正则表达式其实并不难,语法就那么多,而且一旦掌握在某些时候能够给解决问题提供捷径,更重要的是面试可能会被问到,要是不会那就尴尬了。

本文全面介绍正则表达式的语法知识,全面介绍JavaScript中正则表达式的API,通过实战,希望能够帮助大家全面学习,并啃下前端的难题。

正则是啥?

下面是我对正则的理解:

正则就是用有限的符号,表达无限的序列,殆已!

正则表达式的语法一般如下(js),两条斜线中间是正则主体,这部分可以有很多字符组成;i部分是修饰符,i的意思表示忽略大小写

/^abc/i

正则定义了很多特殊意义的字符,有名词,量词,谓词等,下面逐一介绍

简单字符

没有特殊意义的字符都是简单字符,简单字符就代表自身,绝大部分字符都是简单字符,举个例子

/abc/ // 匹配 abc
/123/ // 匹配 123
/-_-/ // 匹配 -_-
/海镜/ // 匹配 海镜

转义字符

\是转义字符,其后面的字符会代表不同的意思,转义字符主要有三个作用:

第一种,是为了匹配不方便显示的特殊字符,比如换行,tab符号等

第二种,正则中预先定义了一些代表特殊意义的字符,比如\w

第三种,在正则中某些字符有特殊含义(比如下面说到的),转义字符可以让其显示自身的含义

下面是常用转义字符列表:

\n 匹配换行符
\r 匹配回车符
\t 匹配制表符,也就是tab键
\v 匹配垂直制表符
\x20 20是2位16进制数字,代表对应的字符
\u002B 002B是4位16进制数字,代表对应的字符
\u002B 002B是4位16进制数字,代表对应的字符
\w 匹配任何一个字母或者数字或者下划线
\W 匹配任何一个字母或者数字或者下划线以外的字符
\s 匹配空白字符,如空格,tab等
\S 匹配非空白字符
\d 匹配数字字符,0~9
\D 匹配非数字字符
\b 匹配单词的边界
\B 匹配非单词边界
\\ 匹配\本身

字符集和

有时我们需要匹配一类字符,字符集可以实现这个功能,字符集的语法用[``]分隔,下面的代码能够匹配a或b或c

[abc]

如果要表示字符很多,可以使用-表示一个范围内的字符,下面两个功能相同

[0123456789]
[0-9]

在前面添加^,可表示非的意思,下面的代码能够匹配a``b``c之外的任意字符

[^abc]

其实正则还内置了一些字符集,在上面的转义字符有提到,下面给出内置字符集对应的自定义字符集

  • . 匹配除了换行符(\n)以外的任意一个字符 = [^\n]
  • \w = [0-9a-zA-Z_]
  • \W = [^0-9a-zA-Z_]
  • \s = [ \t\n\v]
  • \S = [^ \t\n\v]
  • \d = [0-9]
  • \D = [^0-9]

量词

如果我们有三个苹果,我们可以说自己有个3个苹果,也可以说有一个苹果,一个苹果,一个苹果,每种语言都有量词的概念

如果需要匹配多次某个字符,正则也提供了量词的功能,正则中的量词有多个,如?+*{n}{m,n}{m,}

{n}匹配n次,比如a{2},匹配aa

{m, n}匹配m-n次,优先匹配n次,比如a{1,3},可以匹配aaaaaa

{m,}匹配m-∞次,优先匹配∞次,比如a{1,},可以匹配aaaa...

?匹配0次或1次,优先匹配1次,相当于{0,1}

+匹配1-n次,优先匹配n次,相当于{1,}

*匹配0-n次,优先匹配n次,相当于{0,}

正则默认和人心一样是贪婪的,也就是常说的贪婪模式,凡是表示范围的量词,都优先匹配上限而不是下限

a{1, 3} // 匹配字符串'aaa'的话,会匹配aaa而不是a

有时候这不是我们想要的结果,可以在量词后面加上?,就可以开启非贪婪模式

a{1, 3}? // 匹配字符串'aaa'的话,会匹配a而不是aaa

字符边界

有时我们会有边界的匹配要求,比如以xxx开头,以xxx结尾

^[]外表示匹配开头的意思

^abc // 可以匹配abc,但是不能匹配aabc

$表示匹配结尾的意思

abc$ // 可以匹配abc,但是不能匹配abcc

上面提到的\b表示单词的边界

abc\b // 可以匹配 abc ,但是不能匹配 abcc

选择表达式

有时我们想匹配x或者y,如果x和y是单个字符,可以使用字符集,[abc]可以匹配abc,如果x和y是多个字符,字符集就无能为力了,此时就要用到分组

正则中用|来表示分组,a|b表示匹配a或者b的意思

123|456|789 // 匹配 123 或 456 或 789

分组与引用

分组是正则中非常强大的一个功能,可以让上面提到的量词作用于一组字符,而非单个字符,分组的语法是圆括号包裹(xxx)

(abc){2} // 匹配abcabc

分组不能放在[]中,分组中还可以使用选择表达式

(123|456){2} // 匹配 123123、456456、123456、456123

和分组相关的概念还有一个捕获分组和非捕获分组,分组默认都是捕获的,在分组的(后面添加?:可以让分组变为非捕获分组,非捕获分组可以提高性能和简化逻辑

'123'.match(/(?:123)/) // 返回 ['123']
'123'.match(/(123)/)  // 返回 ['123', '123']

和分组相关的另一个概念是引用,比如在匹配html标签时,通常希望<xxx></xxx>后面的xxx能够和前面保持一致

引用的语法是\数字,数字代表引用前面第几个捕获分组,注意非捕获分组不能被引用

<([a-z]+)><\/\1> // 可以匹配 `<span></span>` 或 `<div></div>`等

预搜索

如果你想匹配xxx前不能是yyy,或者xxx后不能是yyy,那就要用到预搜索

js只支持正向预搜索,也就是xxx后面必须是yyy,或者xxx后面不能是yyy

1(?=2) // 可以匹配12,不能匹配22
1(?!2) // 可有匹配22,不能匹配12

修饰符

默认正则是区分大小写,这可能并不是我们想要的,正则提供了修饰符的功能,修复的语法如下

/xxx/gi // 最后面的g和i就是两个修饰符

g正则遇到第一个匹配的字符就会结束,加上全局修复符,可以让其匹配到结束

i正则默认是区分大小写的,i可以忽略大小写

m正则默认情况下,^和只能匹配字符串的开始和结尾,m修饰符可以让和只能匹配字符串的开始和结尾,m修饰符可以让^和只能匹配字符串的开始和结尾,m修饰符可以让和匹配行首和行尾,不理解就看例子

/jing$/ // 能够匹配 'yanhaijing,不能匹配 'yanhaijing\n'
/jing$/m // 能够匹配 'yanhaijing, 能够匹配 'yanhaijing\n'

/^jing/ // 能够匹配 'jing',不能匹配 '\njing'
/^jing/m // 能够匹配 'jing',能够匹配 '\njing'

图形化工具

有时我们会遇到特别复杂的正则,有时候可能不太直观,下面推荐一个图形化展示的工具,我们把涉及到的语法罗列一下

/^[a-z]*[^\d]{1,10}?(aaa|bbb)(?:ccc)$/

可以看到工具能够更快的帮我们理清头绪

JavaScript中的正则

在js中创建正则有两种办法,字面量和new,和创建其他类型变量一样

var reg = /abc/g // 字面量
var reg = new RegExp('abc', 'g') // new方式,意思和上面一样

js中用到正则的地方有两个入口,正则的api和字符串的api,RegExp#test等于RegExp.prototype.test

  • RegExp#test
  • RegExp#exec
  • String#search
  • String#match
  • String#split
  • String#replace

RegExp#test

每个正则实例都有test方法,test的参数是字符串,返回值是布尔值,表示当前正则是否能匹配指定的字符串

/abc/.test('abc') // true
/abc/.test('abd') // false

RegExp#exec

exec使用方法和test一样,只是返回值并不是布尔值,而是返回匹配的结果

匹配成功返回一个数组,数组第一项是匹配结果,后面一次是捕获的分组

/abc(d)/.exec('abcd') // ["abcd", "d", index: 0, input: "abcd"]

此数组还有另外两个参数,input是输入的字符串,index表示匹配成功的序列在输入字符串中的索引位置

如果有全局参数(g),第二次匹配时将从上次匹配结束时继续

var r1 = /ab/
r1.exec('ababab') // ['ab', index: 0]
r1.exec('ababab') // ['ab', index: 0]

var r2 = /ab/g
r2.exec('ababab') // ['ab', index: 0]
r2.exec('ababab') // ['ab', index: 2]
r2.exec('ababab') // ['ab', index: 4]

这一特性可以被用于循环匹配,比如统计字符串中abc的次数

var reg = /abc/g
var str = 'abcabcabcabcabc'
var num = 0;
var match = null;
while((match = reg.exec(str)) !== null) {
    num++
}
console.log(num) // 5

如果匹配失败则返回null

/abc(d)/.exec('abc') // null

String#search

search方法返回匹配成功位置的索引,参数是字符串或正则,结果是索引

'abc'.search(/abc/) // 0
'abc'.search(/c/) // 2

如果匹配失败则返回-1

'abc'.search(/d/) // -1

'abc'.search(/d/) !== -1 // false 转换为布尔值

String#match

match方法也会返回匹配的结果,匹配结果和exec类似

'abc'.match(/abc/) // ['abc', index: 0, input: abc]
'abc'.match(/abd/) // null

如果有全局参数(g),match会返回所有的结果,并且没有index和input属性

'abcabcabc'.match(/abc/g) // ['abc', 'abc', 'abc']

String#split

字符串的split方法,可以用指定符号分隔字符串,并返回数据

'a,b,c'.split(',') // [a, b, c]

其参数也可以使一个正则,如果分隔符有多个时,就必须使用正则

'a,b.c'.split(/,|\./) // [a, b, c]

String#replace

字符串的replace方法,可以将字符串的匹配字符,替换成另外的指定字符

'abc'.replace('a', 'b') // 'bbc'

其第一个参数可以是正则表达式,如果想全局替换需添加全局参数

'abc'.replace(/[abc]/, 'y') // ybc
'abc'.replace(/[abc]/g, 'y') // yyy 全局替换

在第二个参数中,也可以引用前面匹配的结果

'abc'.replace(/a/, '$&b') // abbc $& 引用前面的匹配字符
'abc'.replace(/(a)b/, '$1a') // aac &n 引用前面匹配字符的分组
'abc'.replace(/b/, '$\'') // aac $` 引用匹配字符前面的字符
'abc'.replace(/b/, "$'") // acc $' 引用匹配字符后面的字符

replace的第二个参数也可以是函数,其第一个参数是匹配内容,后面的参数是匹配的分组

'abc'.replace(/\w/g, function (match, $1, $2) {
    return match + '-'
})
// a-b-c-

RegExp

RegExp是一个全局函数,可以用来创建动态正则,其自身也有一些属性

  • $_
  • $n
  • input
  • length
  • lastMatch

来个例子

/a(b)/.exec('abc') // ["ab", "b", index: 0, input: "abc"]

RegExp.$_ // abc 上一次匹配的字符串
RegExp.$1 // b 上一次匹配的捕获分组
RegExp.input // abc 上一次匹配的字符串
RegExp.lastMatch // ab 上一次匹配成功的字符
RegExp.length // 2 上一次匹配的数组长度

实例属性

正则表达式的实例上也有一些属性

  • flags
  • ignoreCase
  • global
  • multiline
  • source
  • lastIndex

还是看例子

var r = /abc/igm;

r.flags // igm
r.ignoreCase // true
r.global // true
r.multiline // true
r.source // abc

lastIndex比较有意思,表示上次匹配成功的是的索引

var r = /abc/igm;
r.exec('abcabcabc')
r.lastIndex // 3

r.exec('abcabcabc')
r.lastIndex // 6

可以更改lastIndex让其重新开始

var r = /abc/igm;
r.exec('abcabcabc') // ["abc", index: 0]

r.exec('abcabcabc') // ["abc", index: 3]
r.lastIndex = 0
r.exec('abcabcabc') // ["abc", index: 0]

实战实例

来几个常用的例子

/(?:0\d{2,3}-)?\d{7}/ // 电话号 010-xxx xxx

/^1[378]\d{9}$/ // 手机号 13xxx 17xxx 18xxx

/^[0-9a-zA-Z_]+@[0-9a-zA-Z]+\.[z-z]+$/ // 邮箱

去除字符串前后空白

str = str.replace(/^\s*|\s*$/g, '')

总结

刻意练习,方能游刃有余,知己知彼,方能百战百胜,正则是前端的一个武器,技多不压身。

到这里你已经学会了正则的语法,并且学会了在js中使用正则的方法,接下来快去实战吧,要想学会正则必须多加练习,正所谓拳不离手曲不离口吗。

到此这篇关于全面学习正则表达式 - 从原理到实战的文章就介绍到这了,更多相关正则表达式原理到实战内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JS正则表达式一条龙讲解(从原理和语法到JS正则)

    正则啊,就像一座灯塔,当你在字符串的海洋不知所措的时候,总能给你一点思路:正则啊,就像一台验钞机,在你不知道用户提交的钞票真假的时候,总能帮你一眼识别:正则啊,就像一个手电筒,在你需要找什么玩意的时候,总能帮你get你要的东西... -- 节选自 Stinson 同学的语文排比句练习<正则> 欣赏了一段文学节选后,我们正式来梳理一遍JS中的正则,本文的首要目的是,防止我经常忘记正则的一些用法,故梳理和写下来加强熟练度和用作参考,次要目的是与君共勉,如有纰漏,请不吝赐教,良辰谢过. 本文既然取题

  • Java object类及正则表达式原理解析

    equals方法 equals方法,用于比较两个对象是否相同 /* 描述人这个类,并定义功能根据年龄判断是否是同龄人 由于要根据指定类的属性进行比较,这时只要覆盖Object中的equals方法 在方法体中根据类的属性值进行比较 */ class Person extends Object{ int age ; //复写父类的equals方法,实现自己的比较方式 public boolean equals(Object obj) { //判断当前调用equals方法的对象和传递进来的对象是否是同

  • Java正则表达式Pattern和Matcher原理详解

    这篇文章主要介绍了Java正则表达式Pattern和Matcher原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 基本使用 Scanner中的使用正则表达式 //Scanner 支持的分组 Scanner cin=new Scanner("red a bbc").useDelimiter("\\s*a\\s*"); System.out.println(cin.next()); System.out.pri

  • 正则表达式匹配解析过程探讨分析(正则表达式匹配原理)

    已经有多篇关于正则表达式介绍的文章,随着我们越来越多使用正则表达式,想对性能做优化.减少我们正则表达式书写匹配Bug.我们不得不进一步深入了解正则表达式执行过程了.下面我们一起学习,分析下正则表达式执行过程.我们会用regexbuddy测试工具分解执行过程,具体工具使用,可以看:正则表达式性能测试工具推荐.优化工具推荐(regexbuddy推荐).要了解正则表达式解析过程前,我们先来熟悉几个概念. 常见正则表达式引擎 引擎决定了正则表达式匹配方法及内部搜索过程,了解它至关重要的.目前主要流行引擎

  • python 正则表达式贪婪模式与非贪婪模式原理、用法实例分析

    本文实例讲述了python 正则表达式贪婪模式与非贪婪模式原理.用法.分享给大家供大家参考,具体如下: 之前未接触过正则表达式,今日看python网络爬虫的源码,里面一行正则表达式匹配的代码初看之下,不是很理解,代码如下: myItems = re.findall('<div.*?class="content".*?title="(.*?)">(.*?)</div>',unicodePage,re.S) ".*?"这种匹配

  • 正则表达式从原理到实战全面学习小结

    目录 正则是啥? 简单字符 转义字符 字符集和 量词 字符边界 选择表达式 分组与引用 预搜索 修饰符 图形化工具 JavaScript中的正则 RegExp#test RegExp#exec String#search String#match String#split String#replace RegExp 实例属性 实战实例 总结 正则表达式,名字听上去就没有吸引力,我发现很多前端对正则表达式了解不深,甚至有些惧怕,每次能够运行全凭运气,更有甚者完全靠复制粘贴. 正则表达式其实并不难,

  • Nodejs 和Session 原理及实战技巧小结

    一 Cookie 因为HTTP协议是没有状态的,但很多情况下是需要一些信息的,比如在用户登陆后.再次访问网站时,没法判断用户是否登陆过.于是就有了cookies,用于在浏览器端保存用户数据,它有如下特点 1 是在客户端浏览器端才有的 2 用于记录信息,大小最大为4K字节 3 如果使用了cookies,那么任何对该域名的访问都会带上cookies 目前新型网站更多的采用浏览器缓存,cookie会存在一些问题,比如你每次往服务器提交请求时,都会带上cookie,无论是你访问的是不是静态图片. coo

  • python 正则表达式学习小结

    在Python中实现正则的方式是通过re(regular expression的缩写)模块来实现的,你可以调用re模块的各种方法来实现不同的功能,下面我们就来说下,在Python中通过re模块可以调用那些方法,以及这些方法的作用都是什么:还有就是正则的实例以及各种特殊符号的含义: 1.re.sub和replace: sub的全拼是substitute,也就是替换的意思:既然知道是替换了,那就很容易用到实例中了,其实replace也是替换的意思,只不过它们的用法不太相同,下面用一个例子来详细说明下

  • hibernate一对多关联映射学习小结

    一对多关联映射  映射原理  一对多关联映射和多对一关联映射的映射原理是一致的,都是在多的一端加入一个外键,指向一的一端.关联关系都是由多端维护,只是在写映射时发生了变化. 多对一和一对多的区别 多对一和一对多的区别在于维护的关系不同: (1)多对一:多端维护一端的关系,在加载多端时,可以将一端加载上来. (2)一对多:一端维护多端的关系,在加载一端时,可以将多端加载上来. 分类 一对多单向关联映射 对象模型 从对象模型中,我们可以看出,Group持有User的一个引用.由于是单向关联,所以数据

  • 每天一篇javascript学习小结(RegExp对象)

    1.正则表达式test方法 var text = "cat, bat, sat, fat"; var pattern = /.at/; if (pattern.test(text)){ alert("The pattern was matched."); } 2.正则的toString()方法 var pattern = new RegExp("\\[bc\\]at", "gi"); alert(pattern.toStrin

  • JavaScript事件学习小结(一)事件流

    相关阅读: JavaScript事件学习小结(五)js中事件类型之鼠标事件 http://www.jb51.net/article/86259.htm JavaScript事件学习小结(一)事件流 http://www.jb51.net/article/86261.htm javaScript事件学习小结(四)event的公共成员(属性和方法) http://www.jb51.net/article/86262.htm JavaScript事件学习小结(二)js事件处理程序 http://www

  • 每天一篇javascript学习小结(String对象)

    1.string对象中可以传正则的函数介绍 /* match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配. 该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置. 语法 stringObject.match(searchvalue) stringObject.match(regexp) searchvalue 必需.规定要检索的字符串值. regexp 必需.规定要匹配的模式的 RegExp 对象.如果该参数不是 RegE

  • javaScript事件学习小结(四)event的公共成员(属性和方法)

    相关阅读: JavaScript事件学习小结(五)js中事件类型之鼠标事件 http://www.jb51.net/article/86259.htm JavaScript事件学习小结(一)事件流 http://www.jb51.net/article/86261.htm javaScript事件学习小结(四)event的公共成员(属性和方法) http://www.jb51.net/article/86262.htm JavaScript事件学习小结(二)js事件处理程序 http://www

  • 详解@ConfigurationProperties实现原理与实战

    在SpringBoot中,当需要获取到配置文件数据时,除了可以用Spring自带的@Value注解外,SpringBoot提供了一种更加方便的方式:@ConfigurationProperties.只要在bean上添加上这个注解,指定好配置文件的前缀,那么对应的配置文件数据就会自动填充到bean中.举个栗子,现在有如下配置: myconfig.name=test myconfig.age=22 myconfig.desc=这是我的测试描述 添加对应的配置类,并添加上注解@Configuratio

  • 详解高性能缓存Caffeine原理及实战

    目录 一.简介 二.Caffeine 原理 2.1.淘汰算法 2.1.1.常见算法 2.1.2.W-TinyLFU 算法 2.2.高性能读写 2.2.1.读缓冲 2.2.2.写缓冲 三.Caffeine 实战 3.1.配置参数 3.2.项目实战 四.总结 一.简介 下面是Caffeine 官方测试报告. 由上面三幅图可见:不管在并发读.并发写还是并发读写的场景下,Caffeine 的性能都大幅领先于其他本地开源缓存组件. 本文先介绍 Caffeine 实现原理,再讲解如何在项目中使用 Caffe

随机推荐