创建正则表达式
1.使用RegExp()构造函数来创建
RegExp()构造函数非常有用,特别是在需要动态创建正则表达式的时候,这种情况往往没办法通过写死在代码中的正则表达式直接量来实现。
例如,如果待检索的字符串是由用户输入的,就必须使用RegExp()构造函数,在程序运行时创建正则表达式
var pattern = new RegExp("s$");
2.使用直接量语法来创建
var pattern = /s$/;
RegExp对象的属性
每个RegExp对象(即正则表达式对象)都有5个属性。
属性 | 属性描述 |
---|---|
source | 只读的字符串,包含正则表达式的文本 |
global | 只读的布尔值,用以说明这个正则表达式是否带有修饰符g |
ignoreCase | 只读的布尔值,用以说明正则表达式是否带有修饰符i |
multiline | 只读的布尔值,用以说明正则表达式是否带有修饰符m |
lastIndex | 可读/写的整数,如果匹配模式带有g修饰符,这个属性存储在整个字符串中下一次检索的开始位置,这个属性会被exec()和test()方法用到,下面会讲到 |
直接量字符
字符 | 匹配 |
---|---|
a-zA-Z0-9 | 匹配自身 |
\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 |
字符类
将直接量字符单独放进方括号内就组成了字符类。一个字符类可以匹配它所包含的任意字符
字符 | 匹配 |
---|---|
[...] | 方括号内的任意字符 |
[^...] | 不在方括号内的任意字符 |
. | 除换行符和其他Unicode行终止符之外的任意字符 |
\w | 任何ASCII字符组成的单词,等价于[a-zA-Z0-9] |
\W | 任何不是ASCII字符组成的单词,等价于[^a-zA-Z0-9] |
\s | 任何Unicode空白符 |
\S | 任何不是Unicode空白符的字符,注意\S和\w不同 |
\d | 任何ASCII数字,等价于[0-9] |
\D | 除了ASCII数字之外的任何字符,等价于[^0-9] |
[\b] | 退格直接量(特例) |
重复
字符 | 含义 |
---|---|
{n,m} | 匹配前一项至少n次,但不能超过m次 |
{n,} | 匹配前一项n次或更多次 |
{n} | 匹配前一项n次 |
? | 匹配前一项0次或者1次,也就是说前一项是可选的。等价于{0,1} |
+ | 匹配前一项一次货多次,等价于{1,} |
* | 匹配前一项0次或多次,等价于{0,} |
非贪婪重复
上表中列出的匹配重复字符是尽可能多地匹配,而且允许后续的正则表达式继续匹配。因此,我们称之为“贪婪的”匹配。
我们同样可以使用正则表达式进行非贪婪匹配。只须在待匹配的字符后跟随一个问号即可:"??"、"+?"、"*?"或"{1,5}?"。
比如,正则表达式 /a+/ 可以匹配一个或多个连续的字母a。当使用 "aaa" 作为匹配字符串时,正则表达式会匹配它的三个字符。但是 /a+?/ 也可以匹配一个或多个连续字母a,但它是尽可能少地匹配。我们同样将 "aaa" 作为匹配字符串,但后一个模式只能匹配第一个a。
使用非贪婪的匹配模式所得到的结果可能和期望并不一致。考虑以下正则表达式 /a+b/ ,它可以匹配一个或多个a,以及一个b。当使用 "aaab" 作为匹配字符串时,它会匹配整个字符串。现在再试一下非贪婪匹配的版本 /a+?b/ ,它匹配尽可能少的a和一个b。当用它来匹配 "aaab" 时,你期望它能匹配一个a和最后一个b。但实际上,这个模式却匹配了整个字符串,和该模式的贪婪匹配一模一样。
这是因为正则表达式的模式匹配总是会寻找字符串中第一个可能匹配的位置。由于该匹配是从字符串的第一个字符开始的,因此在这里不考虑它的子串中更短的匹配。
指定匹配位置
使用正则表达式的锚字符可以指定匹配的位置,可以指定正则表达式的匹配位置实在字符串的开头、结尾还是单词的边界处等。
字符 | 含义 |
---|---|
^ | 匹配正则表达式的开头,在多行检索中,匹配一行的开头 |
$ | 匹配正则表达式的结尾,在多行检索中,匹配一行的结尾 |
\b | 匹配一个单词的边界,简言之,就是位于字符\w和\W之间的位置,或位于字符\w和字符串的开头或者结尾的位置(但是需要注意,[\b]匹配的是退格符) |
\B | 匹配非单词边界的位置 |
(?=p) | 零宽正向先行断言,要求接下来的字符都与p匹配,但不能包含匹配p的那些字符 |
(?!p) | 零宽负向先行断言,要求接下来的字符都不与p匹配 |
修饰符
正则表达式的修饰符,用以说明高级匹配模式的规则。修饰符的位置是放在“/”符号之外的,也就是第二条斜线之后;或者是正则表达式的构造函数的第二个参数位置,
// 正则表达式构造函数的第二个参数,用来指定修饰符
var pattern = new RegExp("s$","igm");
// 直接量语法中,第二条斜线之后,指定修饰符
var pattern = /s$/igm;
字符 | 含义 |
---|---|
i | 执行不区分大小写的匹配 |
g | 执行一个全局匹配,简言之,及找到所有的匹配,而不是找到第一个匹配之后即停止 |
m | 多行匹配模式,^匹配每一行的开头和字符串的开头,$匹配每一行的结束和字符串的结束 |
选择
使用选择符
|
,可以指定匹配的是该符号左边的子表达式还是右边的子表达式。例如:/ab|cd|ef/
可以匹配字符串"ab",也可以匹配字符串"cd",还可以匹配字符串"ef"
字符 | 含义 |
---|---|
| | 匹配的是该符号左边的子表达式还是右边的子表达式 |
分组
分组是把单独的项组合成子表达式,以便可以像处理一个独立的单元那样用
|
、*
、+
或者?
等来对单元内的项进行处理。
不仅如此,分组后的子表达式还可以用于后期的引用,能够更大限度满足我们的需求。
字符 | 含义 |
---|---|
(...) | 组合,将几个项组合为一个单元,这个单元可以通过| 、* 、+ ** 或者? 等符号加以修饰,而且可以记住和组合相匹配的字符串以供此后的引用使用 |
(?:) | 只组合,把项组合到一个单元,但是不记忆和改组相匹配的字符 |
引用
对正则表达式中前一个子表达式的引用,并不是指对子表达式模式的引用,而指的是与那个模式相匹配的文本的引用。
正则表达式中有多个带圆括号的子表达式,可以使用\n
的形式进行引用。
例如:\1
引用的是第一个带圆括号的子表达式,\3
引用的是第三个带
圆括号的子表达式。注意,因为子表达式可以嵌套另一个子表达式,所以它的位置是参与计数的左括号的位置。
字符 | 含义 |
---|---|
\n | 和第n个分组第一次匹配的字符相匹配,组是圆括号中的子表达式(也有可能是嵌套的),组索引是从左到右的左括号书。但是注意:"(?:)"形式的分组不编码,即不能引用 |
用于模式匹配的String方法
1.String.search(n)
- 参数:正则表达式
- 返回值:返回第一个与之匹配的子串的起始位置,如果找不到匹配的子串,它将返回-1。
- 示例代码:
"JavaScript".search(/script/i); // 返回值为4
- 备注:如果search()的参数不是正则表达式,则首先会通过RegExp构造函数将它转换成正则表达式。search()方法不支持全局检索,因为它忽略正则表达式参数中的修饰符g。
2.String.replace(n1,n2)
- 参数:第一个参数是一个正则表达式,第二个参数是要进行替换的字符串
- 作用:
- 这个方法会对调用它的字符串进行检索,使用指定的模式来匹配。
- 如果正则表达式中设置了修饰符g,那么源字符串中所有与模式匹配的子串都将替换成第二个参数指定的字符串。
- 如果不带修饰符g,则只替换所匹配的第一个子串。
- 示例代码:
var text="Hello javascript ! javascript is very good !";
// 将所有不区分大小写的javascript都替换成大小写正确的JavaScript
var text2=text.replace(/javascript/gi,"JavaScript");
// 最终的text2是 "Hello JavaScript ! JavaScript is very good !"
console.log(text2);
- 备注:。如果replace()的第一个参数是字符串而不是正则表达式,则replace()将直接搜索这个字符串,而不是像search()一样首先通过RegExp()将它转换为正则表达式。
3.String.match(n)
- 参数:正则表达式
- 返回值:
- 返回的是一个由匹配结果组成的数组。如果该正则表达式设置了修饰符g,则该方法返回的数组包含字符串中的所有匹配结果。
- 如果这个正则表达式没有设置修饰符g,match()就不会进行全局检索,它只检索第一个匹配。但即使match()执行的不是全局检索,它也返回一个数组。在这种情况下,数组的第一个元素就是匹配的字符串,余下的元素则是正则表达式中用圆括号括起来的子表达式。
- 因此,如果match()返回一个数组a,那么a[0]存放的是完整的匹配,a[1]存放的则是与第一个用圆括号括起来的表达式相匹配的子串,以此类推。
- 示例代码:
var url=/(\w+):\/\/([\w.]+)\/(\S*)/;
var text="Visit my blog at http://www.example.com/~david";
var result=text.match(url);
if(result!=null){
var fullurl=result[0]; //包含"http://www.example.com/~david"
var protocol=result[1]; //包含"http"
var host=result[2]; //包含"www.example.com"
var path=result[3]; //包含"~david"
}
4.String.split(n)
- 参数:正则表达式
- 作用:将传入的参数作为边界条件,将调用它的字符串拆分为一个子串组成的数组
- 返回值:返回拆分后的字符串组成的数组
- 示例代码:
"123,456,789".split(",");//返回["123","456","789"]
"1,2,3,4,5".split(/\s*,\s*/);//返回["1","2","3","4","5"]
用于模式匹配的RegExp方法
1.RegExp.exec(n)
- 参数:字符串
- 作用:exec()方法对一个指定的字符串执行一个正则表达式,简言之,就是在一个字符串中执行匹配检索。
- 返回值:
- 如果它没有找到任何匹配,它就返回null;
- 如果它找到了一个匹配,它将返回一个数组,就像match()方法为非全局检索返回的数组一样。
- 这个数组的第一个元素包含的是与正则表达式相匹配的字符串,余下的元素是与圆括号内的子表达式相匹配的子串。
- 和match()方法不同,不管正则表达式是否具有全局修饰符g,exec()都会返回一样的数组。
- 回忆一下,当match()的参数是一个全局正则表达式时,它返回由匹配结果组成的数组。相比之下,exec()总是返回 当前匹配的一个匹配结果 ,并提供关于本次匹配的完整信息。
- 当调用exec()的正则表达式对象具有修饰符g时,它将把当前正则表达式对象的lastIndex属性设置为紧挨着匹配子串的字符位置。
- 当同一个正则表达式第二次调用exec()时,它将从lastIndex属性所指示的字符处开始检索。如果exec()没有发现任何匹配结果,它会将lastIndex重置为0(在任何时候都可以将lastIndex属性设置为0,每当在字符串中找最后一个匹配项后,在使用这个RegExp对象开始新的字符串查找之前,都应当将lastIndex设置为0)。
- 这种特殊的行为使我们可以在用正则表达式匹配字符串的过程中反复调用exec(),
- 示例代码:
var pattern=/java/img;
var text="I love JAVA and JavaScript. I think javascript is more interesting";
// 第一次调用,返回的信息:["JAVA", index: 7, input: "text的文本内容", groups: undefined]
console.log(pattern.exec(text));
// 第二次调用,返回的信息:["Java", index: 16, input: "text的文本内容", groups: undefined]
console.log(pattern.exec(text));
// 第三次调用,返回的信息:["java", index: 36, input: "text的文本内容", groups: undefined]
console.log(pattern.exec(text));
- 备注:exec()方式是RegExp对象的主要方法,大家仔细阅读上面的介绍,一定能明白这个方法。
2.RegExp.test(n)
- 参数:字符串
- 返回值:用test()对某个字符串进行检测,如果包含正则表达式的一个匹配结果,则返回true,否则返回false。
- 示例代码:
var pattern=/java/i;
pattern.test("JavaScript"); // 返回true
pattern.test("feng"); // 返回false