[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}  使量词作用域分组

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

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

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

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

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

需注意JavaScript不支持后顾

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

你可能感兴趣的:([JavaScript学习笔记]正则表达式)