[JavaScript学习笔记]正则表达式

常用

作用:找到有规则的文本

// 常用
.   // 表示任意字符,不包括回车
\n  // 回车
\d  // 表示数字
\b  // boundary 边界线,跟空格无关,而是词组的组成形式,英语是空格,中文是单字
{n}  // n填数字,匹配前面的多个
\w   // word,匹配字母数字或者下划线
\s   // space 匹配空白符
+   // 前面的字符一个或多个
^   // 开头
$   // 结尾
$1  // 需要放在替换栏,表示匹配到的字符保存下来,$1,$2… 对应前边第n个()包裹的东西 
// 嵌套时从左到右看括号
?   // 可有可无  -?\d+  表示可有负号或者可以没有
[ab]  // a或b
\t   //水平制表符
\v   //垂直制表符
\n   //换行符
\r   // 回车符
\0   // 空字符
\f   // 换页符
\cX  // 与X对应的控制字符(Ctrl+x)

修饰符

  • g : global 全局搜索
  • i : ignore case 忽略大小写
  • m : multiple lines 多行搜索

默认下大小写敏感,且只匹配第一个匹配到的

元字符

* + ? ^ . | \ () {} []

范围类

表示一类,其中有一个即匹配,泛指某个特征的对象
[a-z] 表示所有小写字母
[a-zA-Z] 表示所有字母
[abc] 表示abc归为一类,有其中一个
^负向类,字符类取反
[^abc] 不包含a或b或c

预定义类

字符 等价类 含义
. [^\r\n] 除了回车符和换行符之外的所有字符
\d [0-9] 数字字符
\s [\t\n\xOB\f\r] 空白符 space
\S [^\t\n\xOB\f\r] 非空白符
\w [a-zA-z_0-9] 单词字符(字母\数字\下划线)
\W [^a-zA-z_0-9] 非单词字符
\b 单词边界
\B 非单词边界
^ 以xxx开始 判断依据是前面是否为空白符
$ 以xxx主动放弃

量词

字符 含义
? 出现0次或1次(最多一次)
+ 出现1次或者多次(至少一次)
* 出现0次或者多次(任意次)
{n} 出现n次
{n,m} 出现n到m次
{n,} 至少出现n次

贪婪匹配&懒惰匹配模式

默认为贪婪模式,指有重复限定符时,匹配尽可能多的字符
限定符后使用?则使用懒惰匹配

懒惰匹配限定符

代码/语法 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

栗子

贪婪模式

'123456789'.replace(/\d{3,6}/,'x')
// 'xxxxxx789'

非贪婪模式下,会往最少的匹配

'123456789'.match(/\d{3,6}?/g)
// ['123','456','789']

捕获(分组)

// 自动命名分组
(abc){3}  使量词作用域分组

// 分组命名
(?<name>exp)
(?'name'exp) 命名为name的分组 

// 不捕获(忽略分组)
(?:abc).(ok)  // abc分组被忽略

// 反向引用
'2015-12-25'.replace(/(\d{4})-(\d{2})-(\d{2})/,'$2/$1/$3')  
// 输出"12/25/2015"
// 引用命名  
\k<name>
(?<abc>\d+)_\k<abc>\w+ 
// 可以在同一个正则里面用,在JavaScript RegExp对象方法.replace两个参数里也可以使用用于替换

零宽断言 (Lookahead and Lookbehind Zero-Length Assertions)

  • 前瞻即匹配到规则,向看(方向从文本末尾向开头称为)检查是否符合断言
  • 后顾/后瞻则相反
  • 正向(正预测/正回顾)指条件语句匹配
  • 负向相反

需注意JavaScript不支持后顾

名称 正则 含义
正预测先行断言(正向前瞻) assert(?=exp) assert后面必须匹配exp条件
负预测先行断言(负向前瞻) assert(?!exp) assert后面不能匹配exp条件
正回顾后发断言(正向后顾) assert(?<=exp) JavaScript不支持
负回顾后发断言(负向后顾) assert(?<!exp) JavaScript不支持

JavaScript中构建方式 RegExp 对象

字面量

/\b\w/g
// 斜杠之间为正则对象 斜杠右边为修饰符

构造函数

var reg = new RegExp('\\b\\w','g')
// 两个参数 第一参数注意转义

对象属性

ignoreCase:返回一个布尔值,表示是否设置了i修饰符,该属性只读。
global:返回一个布尔值,表示是否设置了g修饰符,该属性只读。
multiline:返回一个布尔值,表示是否设置了m修饰符,该属性只读。
lastIndex:返回下一次开始搜索的位置。该属性可读写,但是只在设置了g修饰符时有意义。
source:返回正则表达式的字符串形式(不包括反斜杠),该属性只读。

var reg = /abc/igm;
reg.gloabl        // true 返回是否搜索全文 
reg.ignoreCase    // true 返回是否大小写忽略
reg.multiline     // true 返回是否多行匹配
reg.lastIndex     //  0  返回索引位置
reg.source        //  "abc"   返回正则表达式字符串形式

对象方法

RegExp.prototype.test()

返回一个布尔值,表示是否匹配

/apple/.test('牛顿吃苹果')  // false

如果带g修饰符,则每一次test()都从上一次结束的位置开始向后匹配

var reg = /a/g
var string = "apple & apple" 
reg.lastIndex // 0

reg.test(string)  // true 匹配到第一个a
reg.lastIndex // 1  位置是第一个

reg.test(string)  // true 匹配到第二个a
reg.lastIndex // 9  位置是第9个开始

reg.test(string)  // false 匹配不到
reg.lastIndex  // 0 匹配不到了

reg.test(string)  // true 重新匹配到第一个
reg.lastIndex  // 1 位置是第一个

RegExp.prototype.exec(str)

使用正则表达式模式对字符串进行搜索,并更新对象实例的属性,返回匹配结果。如果发现匹配,就返回一个数组,成员是每一个匹配成功的子字符串,否则返回null。

var s = 'cat'
var r1 = /a/
var r2 = /b/

r1.exec(s)  // ["a"]
r2.exec(s)  // null

如果正则表示式包含圆括号()(即含有“组匹配”),则返回的数组会包括多个成员。第一个成员是整个匹配成功的结果,后面的成员就是圆括号对应的匹配成功的组。也就是说,第二个成员对应第一个括号,第三个成员对应第二个括号,以此类推。整个数组的length属性等于组匹配的数量再加1。

var s = '_x_x';
var r = /_(x)/;

r.exec(s) // ["_x", "x"]

上面代码的exec()方法,返回一个数组。第一个成员是整个匹配的结果,第二个成员是圆括号匹配的结果,如果还有则继续匹配并返回到数组内

同时该数组还包含两个属性,需要注意这个与正则实例对象的属性不同
index 匹配成功的开始位置,从0开始计算
input 整个远字符串

var r = /a(p+)/
var arr = r.exec('_apple pine apple')  // 是返回的数组才有属性
arr      // ["app","pp"]
arr.index // 1  位置是第二个
arr.input // "_apple pine apple"

如果使用修饰符g,下一次搜索会从上次成功匹配结束的位置开始

var r = /a(p+)/g
var s = 'apple pine pine apple pine'

var a1 = r.exec(s)
a1 //["app","pp"]
a1.index // 0
r.lastIndex // 3

var a2 = r.exec(s)
a2 //["app","pp"]
a2.index // 16
r.lastIndex // 19

// 如果匹配不到了
var a3 = r.exec(s)
a3 // null
a3.index // TypeError: Cannot read property 'index' of null
r.lastIndex // 0

// 循环了
var a4 = r.exec(s)
a4 //["app","pp"]
a4.index // 0
r.lastIndex // 3

由于其存在循环的情况,我们利用返回的数组判断循环结束,一次循环完成所有匹配

var r = /a(b+)a/g;
var s = '_abbba_aba_';

while(true) {
  var match = r.exec(s);
  if (!match) break; //当数组结果不存在时就跳出循环
  console.log(match[1]);  
}
// bbb
// b

如果设置了lastIndex属性,就会从lastIndex位置开始匹配,需要g修饰符才生效

var r1 = /a(p+)/
r1.lastIndex = 5 
var a1 = r1.exec('apple pine apple')
a1.index  // 0
r1.lastIndex // 3
// 由于没有g 所以无效

var r2 = /a(p+)/g
r2.lastIndex = 5 
var a2 = r2.exec('apple pine apple')
a2.index  // 11
r2.lastIndex // 14
// 有g修饰符,所以生效

字符串对象方法 search() | match() | replace() | split()

search()

返回匹配结果的在字符串中的位置,g修饰符无效,因此lastIndex属性也无效

'apple pine apple'.search(/a(p+)/)
// 0  
// 第一个位置,从0 开始数
'apple pine apple'.search(/bba/)
// -1 
// 没匹配到

var r = /a(p+)/g;
r.lastIndex = 5; // 无效
'apple pine apple'.search(r) // 0

match()

返回匹配成功的的结果的数组,失败则返回null,g无效

var s = 'apple pine'
s.match(/a(p+)/)  // ["app", "pp"]
s.match(/b(a+)/)  // null

var r = /a(p+)/g 
r.lastIndex = 5
s.match(r)  // ["app", "pp"]
r.lastIndex  // 0 
// g修饰符无效

replace()

接受两个参数,第一个为搜索模式,第二个为替换内容,有g修饰符时替换所有字符

var s = 'apple'
s.replace(/p/,'b') // "abple"
s.replace(/p/g,'b') // "abble"

// 清除字符串两端空白符
var str = '  #id div.class  ';
str.replace(/^\s+|\s+$/g, '')
// "#id div.class"

replace()方法的第二个参数可以使用美元符号$,用来指代所替换的内容

$& 指代匹配的子字符串。
$` 指代匹配结果前面的文本。
$' 指代匹配结果后面的文本。
$n 指代匹配成功的第n组内容,n是从1开始的自然数。
$$ 指代美元符号$。
'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1')
// "world hello"

'abc'.replace('b', '[$`-$&-$\']')
// "a[a-b-c]c"

第二个参数还可以是函数,将匹配内容替换为函数返回值
该函数可接受多个参数,第一个为捕捉的内容match,第二个为第二个参数是捕捉到的组匹配(有多少个组匹配,就有多少个对应的参数)。此外,最后还可以添加两个参数,倒数第二个参数是捕捉到的内容在整个字符串中的位置(比如从第五个位置开始),最后一个参数是原字符串。

var prices = {
  'pr_1': '$1.99',
  'pr_2': '$9.99',
  'pr_3': '$5.00'
};

var template = '/* ... */'; // 这里可以放网页模块字符串

template.replace(
  /(<span id=")(.*?)(">)(<\/span>)/g,
  function(match, $1, $2, $3, $4){
    return $1 + $2 + $3 + prices[$2] + $4;
  }
);

split()

字符串对象按正则规则分割,返回分割后组成的数组,接受两个参数,第一个为分割规则,第二个为最大成员数

// 非正则分隔
'a,  b,c, d'.split(',')
// [ 'a', '  b', 'c', ' d' ]

// 正则分隔,去除多余的空格
'a,  b,c, d'.split(/, */)
// [ 'a', 'b', 'c', 'd' ]

// 指定返回数组的最大成员
'a,  b,c, d'.split(/, */, 2)
[ 'a', 'b' ]

// 组匹配成员也会返回到数组
'aaa*a*'.split(/(a*)/)
// [ '', 'aaa', '*', 'a', '*' ]

参考:

http://javascript.ruanyifeng.com/stdlib/regexp.html
https://regexper.com/
http://www.regular-expressions.info/lookaround.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • 初衷:看了很多视频、文章,最后却通通忘记了,别人的知识依旧是别人的,自己却什么都没获得。此系列文章旨在加深自己的印...
    DCbryant阅读 3,982评论 0 20
  • 带你入门(几个小小点) 目录 正则表达式的使用 正则表达式的基本构成元素 正则中的类(分类),基本的元字符 + 五...
    南航阅读 685评论 0 2
  • 什么是正则表达式 Regular Expression使用单个字符串来描述,匹配一系列符合某个句法规则的字符串 说...
    打铁大师阅读 775评论 1 6
  • 1. 概述 正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符...
    JRG_Orange阅读 2,511评论 0 50
  • OLED 和 LCD OLED主动发光,而LCD需要背光源(目前主流为LED背光),虽然OLED先天在黑位表现和动...
    水陌轻寒阅读 438评论 0 0