简介
正则表达式,又称正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。
说人话就是:对字符串执行模式匹配的强大工具。
Javascript中的正则表达式相较于其他语言来说实现的并不完整,但仍然是十分强大的,能够帮助我们完成绝大多数模式匹配任务。
定义
在javascript中,正则表达式的定义和数组以及对象的定义一样有俩种方式。 一种是直接量,另一种是构造函数。
直接量
Javascript可以使用类似Perl的语法定义一个正则表达式
var r = /pattern/flags;
其中pattern是任何简单或复杂的正则表达式,flags是用以表达正则表达式行为的一个或者多个标识。
flags
- g 表示全局(global)模式,即模式将被应用于所有字符串
- i 表示不区分大小写
- m 多行模式
举个栗子:
var reg1 = /ip/g; // 匹配字符串中所有'ip'的实例
var reg2 = /com/gi; // 匹配以'com'结尾的三个字符的组合,不区分大小写
使用构造函数
Javascript中正则表达式的构造函数为RegExp,即Regular Expression的缩写,它接收两个参数,第一个为要匹配的字符串模式,另一个是可选的标识位。
var reg = new RegExp('nice', 'g'); // 匹配字符串中所有的'nice'
注意:第一个参数是一个字符串nice
,而不是正则表达式的直接量/nice/
。
双重转义
所有元字符都需要进行双重转义
所有元字符都需要进行双重转义
所有元字符都需要进行双重转义
使用构造函数
定义正则表达式,由于构造函数的第一个参数必须是一个字符串,在匹配元字符时,需要双重转义。
// 匹配{user}
var reg1 = new RegExp('\{user\}', 'g'); // wrong
// 由于\在字符串中需要转义为\\,所以,如果要匹配{user},正则表达式需要写为
var reg1 = new RegExp('\\{user\\}', 'g');
基本概念总结
元字符
在正则表达式的模式中,有一些字符是有特殊含义的,被称为元字符,如果要匹配元字符,则必须对其进行转义,如果用构造函数,则要进行双重转义。
这些元字符分别是(一共14个):
{ ( [ \ ^ $ | ? * + . ] ) }
直接量字符
字符 | 匹配 |
---|---|
字母数字字符 | 自身 |
\0 | 查找 NUL 字符。 |
\n | 查找换行符。 |
\f | 查找换页符。 |
\r | 查找回车符。 |
\t | 查找制表符。 |
\v | 查找垂直制表符。 |
\xxx | 查找以八进制数 xxx 规定的字符。 |
\xdd | 查找以十六进制数 dd 规定的字符。 |
\uxxxx | 查找以十六进制数 xxxx 规定的 Unicode 字符。 |
不管一个直接量字符字符代表何种含义,单个字符始终只匹配单个字符
字符类
字符 | 等价于 | 匹配 |
---|---|---|
. | [^\n\r] | 查找单个字符,除了换行和行结束符。 |
\w | [a-zA-Z_0-9] | 任意ASCII单字字符,等价于[a-zA-Z0-9_] |
\W | [^a-zA-Z_0-9] | 查找非单词字符。 |
\d | [0-9] | 查找数字。 |
\D | [^0-9] | 查找非数字字符。 |
\s | [ \t\n\x0B\f\r] | 查找空白字符。 |
\S | [^ \t\n\x0B\f\r] | 查找非空白字符。 |
[] | 来表示单个字符有或的关系,如/[bc]/,匹配b或者c | |
^ | 来表示不匹配后面跟着的字符,如/[^bc],/不匹配b或c | |
- | 来表示一个范围,如/[a-z]/,匹配a-z的字母,可以和负向类结合/^0-9/ | |
组合类: | 以上几种类组合而成的字符类,如/a-z0-9\n/,匹配a-z的字母或者0-9的数字或者换行符 |
注意:在javascript类不能嵌套,就是不支持联合类和交叉类,/a-m[p-z]/和/a-m[^b-e]/在JavaScript中是非法的
锚字符
字符 | 含义 |
---|---|
^ | 匹配字符串的开头,在多行检索中,匹配一行的开头 |
$ | 匹配字符串的结尾,在多行检索中,匹配一行的结尾 |
\b | 匹配单词边界。 |
\B | 匹配非单词边界。 |
量词
简单量词
常用量词 | {m,n}等价形式 | 描述 |
---|---|---|
? | {0,1} | 最多出现1次,例如,do(es)? 匹配 do 或 does 中的 do |
* | {0,} | 可能出现,也可能不出现,出现次数无上限,例如,zo* 匹配 z 和 zoo。 |
+ | {1,} | 最少出现1次,例如,zo+ 匹配 zo 和 zoo,但不匹配 z |
在正则表达式概念中,称 +、*、?为常用量词,称{n,m}形式的为通用量词。
使用情景举例
**?的使用
**
情景:美式应用和英式语言的单词写法不同,比如traveler和traveller.
var str1 = 'traveler';
var str2 = 'traveller';
var pattern = /travell?er/;
console.log(pattern.test(str1));
console.log(str2.search(str2));
结果打印:
true
0
匹配各类标签(前端应用)
- 匹配所以tag: /<[^>]+>/
- 匹配open tag: /<[/>][>]*>/
- 匹配close tag: /</[^>]+>/
- 匹配self-closing tag: /[^>/]+/>/
复杂量词
- 贪婪量词:先匹配整个字符串,如果不匹配则去掉最后一个字符再匹配,直到没有任何字符。它是从后向前匹配。
所有简单量词都是贪婪的
。 - 惰性量词:和贪婪量词相反,即先匹配第一个字符,不匹配则匹配第一第二个字符,直到最后整个字符串。
所有简单量词后面加?就是惰性的了
。 - 支配量词:只匹配整个字符串一次,不匹配就结束,也称最懒量词,
所有简单量词后面加+就是支配的了,但是javascript不支持,所以它连出场的机会也没有了。
。
举个栗子(complex-quantifiers.js):
var re1 = /.*bbb/g; // 定义贪婪量词
var re2 = /.*?bbb/g; // 定义简单惰性
// var re3 = /.*+bbb/g;//支配性,javascript不支持,nodejs报错
var str='abbbaabbbaaabbb1234';
console.log(re1.test(str)); //true
console.log(re1.exec(str)); //null
console.log(str.match(re1)); //abbbaabbbaaabbbb
console.log(re2.test(str)); //true
console.log(re2.exec(str)); //aabbb
console.log(str.match(re2)); //abbb,aabbb,aaabbb
分组
到目前为止,我们只能一个字符到匹配,虽然量词的出现,能帮助我们处理一排密紧密相连的同类型字符。但这是不够的,下面该轮到小括号出场了,中括号表示范围内选择,大括号表示重复次数。小括号允许我们重复多个字符。
举个栗子(group.js):
//分组+量词
console.log(/(dog){2}/.test("dogdog"))//true
//分组+范围
console.log("baddad".match(/([bd]ad?)*/))//baddad,dad
//分组+分组
console.log("mon and dad".match(/(mon( and dad)?)/))//mon and dad,mon and dad, and dad
优先级
优先级 | 符号 | 说明 |
---|---|---|
最高 | 转义符 | |
高 | ( )、(?: )、(?= )、[ ] | 单元和字符类 |
中 | *、+、?、{n}、{n,}、{m,n} | 量词 |
低 | ^、$、\任何元字符、任何字符 | 描点 |
最低 | | | 替换,选择 |
参考加减乘除,先算括号内的记忆方式
RegExp对象
RegExp属性
global 属性 | ignoreCase 属性 | multiline 属性 | source 属性
- global: 返回布尔值,该值指示使用正则表达式的 global 标志 (g) 的状态。 默认值为 false。
只读。
- ignoreCase: 返回布尔值,该值指示在正则表达式中使用的 ignoreCase 标志 (i) 的状态。 默认值为 false。
只读。
- multiline: 返回布尔值,该值指示在正则表达式中使用的 multiline 标志 (m) 的状态。 默认值为 false。
只读。
- source: 返回正则表达式模式的文本的一个副本。 只读。
- lastIndex: 如果使用了全局模式,这个变量保存的是字符串中尝试下次匹配的偏移值。在exec和test中都会用到这个变量。
可写
RegExp方法
RegExp 对象有 3 个方法:test()、exec() 以及 compile()
RegExp.test(string)
test 方法检查字符串中是否存在某种模式,如果存在,则返回 true,否则返回 false。test 方法不修改全局 RegExp 对象的属性。
语法:
rgExp.test(str)
// 参数
rgExp 必需。 包含正则表达式模式和适用标志的 Regular Expression 对象的实例。
str 必需。 将对其执行搜索的字符串。
栗子:
var str = 'huangge is an handsome man';
var reg1 = new RegExp( 'handsome', 'g' );
var result = reg1.test(str);
console.log('huangge is an handsome man: ' + result);
RegExp.exec(string)
exec 方法使用正则表达式模式对字符串执行需找匹配,如果成功,则返回表示匹配信息的数组,否则返回null。默认情况下,它返回第一次匹配的结果
语法:
rgExp.exec(str)
// 参数
rgExp 必需。 包含正则表达式模式和适用标志的 Regular Expression 对象的实例。
str 必需。 对其执行搜索的 String 对象或字符串文本。
返回值
如果成功匹配,exec 方法返回一个数组,并且更新正则表达式对象的属性。返回的数组包括匹配的字符串作为第一个元素,紧接着一个元素对应一个成功匹配被捕获的字符串的捕获括号(capturing parenthesis)。
如果匹配失败,exec 方法将返回 null。
栗子(regexp-exec.js):
var reg= /\d{4}-\d{2}-\d{2}/g;
var str = 'aaa2015-08-11aaaaaabbss2015-08-22bbb';
var result = reg.exec(str);
console.log(result);
结果如下:
[ '2015-08-11',
index: 3,
input: 'aaa2015-08-11aaaaaabbss2015-08-22bbb' ]
RegExp.compile(string)
将正则表达式编译为内部格式,从而更快地执行。
语法:
rgExp.compile(pattern, [flags])
// 参数
rgExp 必需。 Regular Expression 对象的一个实例。 可以是变量名或文本。
pattern 必需。 一个字符串表达式,包含要编译的正则表达式模式
flags 可选。 可以组合使用的可用标志有:
g(全局搜索出现的所有模式)
i(忽略大小写)
m(多行搜索)
compile 方法将 pattern 转换为内部的格式,从而执行得更快。 例如,这允许在循环中更有效地使用正则表达式。 当重复使用相同的表达式时,编译过的正则表达式使执行加速。 然而,如果正则表达式发生更改,则这种编译毫无益处。
String的正则方法
String.match(RegExp)
这个方法类似RegExp.exec(string),只是调换了RegExp和string的位置。 另一个区别就是,无论是否指定全局,RegExp.exec(string)只是返回单词匹配结果。 而string.match()会返回一个字符串数组,其中包含了各次匹配成功的文本
举个栗子(string-match.js):
var reg= /\d{4}-\d{2}-\d{2}/g;
var str = 'aaa2015-08-11aaaaaabbss2015-08-22bbb';
var result = str.match(reg);
console.log(result);
打印的结果为:
[ '2015-08-11', '2015-08-22' ]
String.search(RegEexp)
这个用来寻找某个正则表达式在字符串第一次匹配成功的位置,如果不成功,则返回-1
举个栗子(string-search.js):
var str1 = 'sssssaa111';
var str2 = 'sssssaaaaa';
var pattern = /\d/;
console.log ('st1 ' + str1.search(pattern));
console.log ('st2 ' + str2.search(pattern));
打印的结果为:
st1 7
st2 -1
String.replace(RegExp,replacement)
这个方法用来正则表达式替换。 将匹配到的文本替换为replacement。默认情况替换一次。如果设定了全局模式,则所有能匹配的文本都会替换。
举个栗子(string-replace.js):
var reg = /\d{4}-\d{2}-\d{2}/;
var str = '2015-08-11 2015-08-22';
console.log(str.replace(reg, 'Date:'));
打印的结果为:
ate: 2015-08-22
String.split(RegExp [,limit])
这个方法使用一个正则表达式切分字符串,正则表达式是否使用全局对结果没有影响
举个栗子(string-split.js):
var str = 'one two three four';
var pattern = /\s+/;
console.log(str.split(pattern))
打印的结果为:
[ 'one', 'two', 'three', 'four' ]
常用的正则表达式
匹配中文字符的正则表达式: [\u4e00-\u9fa5]
匹配双字节字符(包括汉字在内):[^\x00-\xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)匹配空白行的正则表达式:\n\s*\r
匹配HTML标记的正则表达式:<(\S?)[^>]>.?</\1>|<.? />
匹配首尾空白字符的正则表达式:^\s|\s$
匹配Email地址的正则表达式:\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*
匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}
匹配腾讯QQ号:[1-9][0-9]{4,}
匹配中国邮政编码:[1-9]\d{5}(?!\d)
匹配身份证:\d{15}|\d{18}
匹配ip地址:\d+.\d+.\d+.\d+
匹配特定数字
^[1-9]\d*$ //匹配正整数
^-[1-9]\d*$ //匹配负整数
^-?[1-9]\d*$ //匹配整数
^[1-9]\d*|0$ //匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$ //匹配非正整数(负整数 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ //匹配正浮点数
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ //匹配负浮点数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ //匹配浮点数
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ //匹配非正浮点数(负浮点数 + 0)
匹配特定字符串
^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
^\w+$ //匹配由数字、26个英文字母或者下划线组成的字符串