正则表达式是用正则表达式语言创建的,正则表达式语言并不是一种完备的程序设计语言,它甚至算不上是一种能够直接安装并运行的程序。更准确地说,正则表达式语言是内置于其他语言或软件产品的“迷你”语言。正则表达式语言虽然也被称为一种语言,但它与人们对语言的印象相去甚远。
正则表达式经常被简称为模式
。
js中的正则表达式用RegExp
对象表示,有两种方式创建RegExp
对象。
一种是通过一种特殊的直接量语法创建
var pattern = /s$/
另一种是使用RegExp()
构造函数
var pattern = new RegExp('s$')
如果需要修饰符
var pattern = /s$/i
var pattern = new RegExp('s$', 'i')
js中的正则表达式还是比较弱的,比如不支持后行断言,不支持嵌入条件。
直接量字符包括字面含义的字母和数字、非字母的字符、和一些具有特殊含义的字符,后面两种需要转义。
字符 | 匹配 |
---|---|
字母和数字 | 自身 |
\o | NUL字符(\u0000) |
\t | 制表符(\u0009) |
\n | 换行符(\u000A) |
\v | 垂直制表符(\u000B) |
\f | 换页符(\u000C) |
\r | 回车符(\u000D) |
\xnn | 由十六进制数nn指定的拉丁字符,例如,\x0A等价于\n |
\uxxxx | 由十六进制数xxxx指定的Unicode字符,例如\u0009等价于\t |
\cX | 控制字符^X,例如,\cJ等价于换行符\n |
Windows使用\r\n
表示文本行结束,Unix、Linux只使用\n
表示文本结束。
一些具有特殊含义的字符也需要转义,如下
^ $ . * + ? = ! : | \ / ( ) [ ] { }
将直接量字符单独放进方括号内就组成了字符类,一个字符类可以匹配它所包含的任意字符。由于某些字符类非常常用,因些在js的正则表达式语法中,使用了特定字符的转义字符来表示它们。
字符 | 匹配 |
---|---|
[…] | 方括号内的任意字符 |
[^…] | 不在方括号内的任意字符 |
. | 除换行符和其他Unicode行终止符之外的任意字符 |
\w | 任何ASCII字符组成的单词,等价于[a-zA-Z0-9] |
\W | 任何不是ASCII字符组成的单词,等价于[^a-zA-Z0-9] |
\s | 任何Unicode空白符 |
\S | 任何非Unicode空白符 |
\d | 任何ASCII数字,等价于[0-9] |
\D | 任何非ASCII数字,等价于[^0-9] |
[\b] | 退格直接量(特例) |
字符 | 匹配 |
---|---|
{n, m} | |
{n,} | |
{n} | |
? | 等价于{0, 1} |
+ | 等价于{1,} |
* | 等价于{0,} |
默认情况下,正则表达式会尽可能多地匹配(贪婪模式),只需要在重复字符后面添加问号?
就可以进行非贪婪模式,如??
、+?
、*?
、{1, 5}?
。
需要注意的是,不管是贪婪模式还是非贪婪模式,正则表达式总是会寻找字符串中第一个可能匹配的位置,如,对于字符串aaabb
,/a+b/
会匹配aaabb
,/a+?b/
会匹配aaab
而不是子串中更短的ab
。
选择项的尝试匹配次序是从左到右,直到发现了匹配项,如果左边的选择项匹配,就忽略右边的匹配项,如字符串ab
,/a|ab/
匹配的是a
。
字符 | 匹配 |
---|---|
| | 匹配的是该符号左边的子表达式或右边的子表达式 |
分组形成子表达式。
字符 | 匹配 |
---|---|
(…) | |
(^…) | 只分组,不编号,即不能被引用 |
\n | 回溯引用 |
回溯引用(backreference)允许正则表达式模式引用前面的匹配结果。
字符 | 匹配 |
---|---|
^ | 字符串的开头 |
$ | 字符串的结尾 |
\b | 单词的边界 |
\B | 非单词边界的位置 |
(?=p) | 正向先行断言,要求接下来的字符都与p匹配,但匹配的结果不包括p |
(?!p) | 负向先行断言,要求接下来的字符都不与p匹 |
锚字符是匹配位置的,不匹配任何字符,比如对于字符串abc
,a(?=b)bc
可以匹配,但是a(?=b)c
不匹配。
js支持三个修饰符。
字符 | 匹配 |
---|---|
i | |
g | 执行一个全局匹配,即找到所有的匹配,而不是在找到一个之后就停止 |
m | 多行匹配模式,^匹配一行的开头和字符串的开头,$匹配一行结尾和字符串的结尾 |
RegExp对象有5个属性和2个方法:
5个属性
source
只读,正则表达式的文本
global
只读,是否带有修改符g
ignoreCase
只读,是否带有修改符i
multiline
只读,是否带有修改符m
lastIndex
可读/写,如果匹配模式带有g,这个属性存储整个字符串下一次检索的开始位置
2个方法
exec()
如果没有找到任何匹配,则返回null,否则返回一个数组,第一个元素包含的是与正则表达式相匹配的字符串,余下的元素是与圆括号内的子表达式相匹配的子串。
会忽略g。
test()
如果匹配则返回true
(1) search
不支持全局检索,会忽略g。
var pattern = /c{2}/
var str = ‘abcdeccfg’
console.log(str.search(pattern)) // 5
// 如果参数不是正则表达式,则会先通完RegExp()转换成正则表达式
var pattern = ‘c{2}’
var str = ‘abcdeccfg’
console.log(str.search(pattern)) // 5
(2) replace
如果replace()的第一个参数是字符串而不是正则表达式,则将直接搜索这个字符串;
如果不带g
,则只匹配一次;
第二个参数可以是$加数字
,代表对应的子串。
(3) match
如果没有g
,则返回结果和exec()
一样
var pattern = /h(i)/
var str = 'ahibchhidefhiig'
console.log(str.match(pattern)) // ["hi", "i", index: 1, input: "ahibchhidefhiig"]
如果有g
,则返回所有的匹配,但不包括子表达式
// 如果有`g`,则返回所有的匹配,但不包括子串
var pattern = /h(i)/g
var str = 'ahibchhidefhiig'
console.log(str.match(pattern)) // ["hi", "hi", "hi"]
(4) split
console.log('123,456,789'.split(',')) // ["123", "456", "789"]
// 好像会忽略`g`
console.log('123, 456 , 789'.split(/\s*,\s*/)) // ["123", "456", "789"]