正则速查

正则

概述

是一种表达式模板,用于匹配文本
创建正则实例的两种方法
6
1
2
var regex = /xyz/;
var regex = new RegExp('xyz');

实例方法 test,exec

正则实例对象的test方法返回一个布尔值,表示当前模式是否能匹配参数字符串。
6
1
/cat/.test('cats and dogs') // true
正则实例对象的exec()方法,用来返回匹配结果。如果发现匹配,就返回一个数组,成员是匹配成功的子字符串,否则返回null。
6
1
2
3
4
5
6
var s = '_x_x';
var r1 = /x/;
var r2 = /y/;

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

字符串实例方法 match,replace,split

字符串的实例方法之中,有4种与正则表达式有关。
  • String.prototype.match():返回一个数组,成员是所有匹配的子字符串。
  • String.prototype.search():按照给定的正则表达式进行搜索,返回一个整数,表示匹配开始的位置。
  • String.prototype.replace():按照给定的正则表达式进行替换,返回替换后的字符串。
  • String.prototype.split():按照给定规则进行字符串分割,返回一个数组,包含分割后的各个成员。

匹配规则

元字符(点字符,位置字符,选择字符)

点字符

 点字符(.)匹配除回车(\r)、换行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)以外的所有字符。
 注意,对于码点大于0xFFFF字符,点字符不能正确匹配,会认为这是两个字符。
6
1
2
/c.t/
// 可以匹配 c 和 t 中间任意单个字符的情况 如 cat c-t, 但不匹配coot

位置字符

位置字符用来提示字符所处的位置,主要有两个字符。
^表示必须出现在开头
$表示必须出现在结尾
6
1
2
3
4
5
/^test/.test('test123'); // true

// 从开始位置到结束位置只有test
/^test$/.test('test'); // true
/^test$/.test('test test'); // false

选择符

表示或关系,即cat|dog表示匹配cat或dog。
6
1
/11|22/.test('911') // true

字符类( [ ] )

字符类(class)表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内,
比如[xyz] 表示x、y、z之中任选一个匹配。
6
1
2
/[abc]/.test('hello world'); // false
/[abc]/.test('apple'); // true

脱字符

如果方括号内的第一个字符是[^],则表示除了字符类之中的字符,其他字符都可以匹配。
比如,[^xyz]表示除了x、y、z之外都可以匹配。
6
1
2
/[^abc]/.test('bbc news'); // true
/[^abc]/.test('bbc'); // false

连字符

某些情况下,对于连续序列的字符,连字符(-)用来提供简写形式,表示字符的连续范围。
比如,[abc]可以写成[a-c],[0123456789]可以写成[0-9],同理[A-Z]表示26个大写字母。
6
1
2
/a-z/.test('b'); // false  没有写在中括号中
/[a-z]/.test('b'); // true

预定义模式

  • \d 匹配0-9之间的任一数字,相当于[0-9]。
  • \D 匹配所有0-9以外的字符,相当于[^0-9]。
  • \w 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]。
  • \W 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]。
  • \s 匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]。
  • \S 匹配非空格的字符,相当于[^ \t\r\n\v\f]。
  • \b 匹配词的边界。
  • \B 匹配非词边界,即在词的内部。
6
1
2
3
4
5
var html = "<b>Hello</b>\n<i>world!</i>";

/[\S\s]*/.exec(html)[0]
// "<b>Hello</b>\n<i>world!</i>"
//上面代码中,[\S\s]指代一切字符。

重复类

模式的精确匹配次数,使用大括号({})表示。{n}表示恰好重复n次,{n,}表示至少重复n次,
{n,m}表示重复不少于n次,不多于m次。
6
1
2
/lo{2}k/.test('look'); // true
/lo{2,5}k/.test('looook') // true

量词符

量词符用来设定某个模式出现的次数。
  • ? 问号表示某个模式出现0次或1次,等同于{0, 1}。

  • * 星号表示某个模式出现0次或多次,等同于{0,}。

  • + 加号表示某个模式出现1次或多次,等同于{1,}。

    这三个量词符默认是贪婪模式,即匹配到下一个字符不满足为止

6
1
2
var s = 'aaa';
s.match(/a+/) // ["aaa"]
在量词符后加上 ? 可以改为非贪婪模式
6
1
2
var s = 'aaa';
s.match(/a+?/) // ["a"]

修饰符 (i,g,m,s,u)

i,g,m,可同时使用

g修饰符

一般第一次匹配成功后,正则对象就停止向下匹配了。g修饰符表示全局匹配(global),
加上它以后,正则对象将匹配全部符合条件的结果,主要用于搜索和替换。
6
1
2
3
4
'a bird lying in the bed'.match(/b\w*/);
// 返回 ['bird', index: 2, input: 'a bird lying in the bed', groups: undefined]
'a bird lying in the bed'.match(/b\w*/g)
// ['bird', 'bed']
此处的\w代表匹配任意的字母、数字和下划线, *代表这个\w出现0次或多次

i修饰符

默认情况下,正则对象区分字母的大小写,加上i修饰符以后表示忽略大小写
6
1
2
/abc/.test('ABC'); // false
/abc/i.test('ABC') // true

m修饰符

m修饰符表示多行模式(multiline),会修改^和$的行为。默认情况下(即不加m修饰符时),^和$匹配字符串的
开始处和结尾处,加上m修饰符以后,^和$还会匹配行首和行尾,即^和$会识别换行符(\n)。
6
1
2
/world$/.test('hello world\n');// false
/world$/m.test('hello world\n') // true
上面的代码中,字符串结尾处有一个换行符。如果不加m修饰符,匹配不成功,因为字符串的结尾不是world;
加上以后,$可以匹配行尾。

s修饰符

正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,
这个可以用u修饰符解决;另一个是行终止符(line terminator character)。主要就是 换行\n以及回车\r,
但有时候我们就是想能够匹配任意字符,es5中有一种变通的方法,使用 [^] 代替. ,
在ES2018中引入了s修饰符,它使得.可以匹配任意单个字符
6
1
2
3
4
5
/foo.bar/.test('foo\nbar');
// false
/foo[^]bar/.test('foo\nbar');
// true
/foo.bar/s.test('foo\nbar'); // true

组匹配

正则表达式的括号表示分组匹配,括号中的模式可以用来匹配分组的内容。
6
1
2
/fred+/.test('fredd'); // true
/(fred)+/.test('fredfred') // true
上面代码中,第一个模式没有括号,结果+只表示重复字母d,第二个模式有括号,结果+就表示匹配fred这个词。
6
1
2
3
var m = 'abcabc'.match(/(.)b(.)/);
m
// ['abc', 'a', 'c']
可以看到 组匹配的内容 a, c 也被输出了出来

正则表达式内部,还可以用\n引用括号匹配的内容,n是从1开始的自然数,表示对应顺序的括号。
6
1
/y(..)(.)\2\1/.test('yabccab') // true
组匹配非常有用,下面是一个匹配网页标签的例子。
6
1
2
3
4
var tagName = /<([^>]+)>[^<]*<\/\1>/;

tagName.exec("<b>bold</b>")[1]
// 'b'
匹配时间的例子
6
1
2
3
4
5
6
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31
组匹配的一个问题是,每一组的匹配含义不容易看出来,而且只能用数字序号(比如matchObj[1])引用,要是组的顺序变了,引用的时候就必须修改序号。

ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
6
1
2
3
4
5
6
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // "1999"
const month = matchObj.groups.month; // "12"
const day = matchObj.groups.day; // "31"
上面代码中,“具名组匹配”在圆括号内部,模式的头部添加“问号 + 尖括号 + 组名”(?<year>),然后就可以在exec方法返回结果的groups属性上引用该组名。同时,数字序号(matchObj[1])依然有效。
引用具名组
6
1
2
3
4
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;

'2015-01-02'.replace(re, '$<day>/$<month>/$<year>')
// '02/01/2015'
正则内部引用具名匹配组,使用 \k<组名>的写法
6
1
2
3
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false

正则速查
http://samkallon.top/blog/2023/01/16/正则速查/
作者
samkallon
发布于
2023年1月16日
许可协议