curTain

作为一个前端,正则是必须要会的技能之一,所以,让我们开始学习正则吧。

这是正则学习的第一篇文章…

前言

正则,用简短的一句话概括,正则表达式是匹配模式,要么匹配字符,要么匹配位置。

正则的方法和与正则有关的方法

共有6个,字符串实例4个,正则实例2个:

String#search

String#split

String#match

String#replace

RegExp#test

RegExp#exec

定义:正则去匹配字符串,如果匹配成功,就返回匹配成功的位置,匹配失败就返回-1.

例子:

1
2
3
4
var regex = /\d/;
var string = "abc123";
console.log( string.search(regex) );
// => 3

2.split

定义:split()方法把原字符串分割成子字符串组成数组,并返回该数组。

语法:str.split(separator, limit)

两个参数均是可选的,其中 separator 表示分隔符,它可以是字符串也可以是正则表达式。如果忽略 separator,则返回的数组包含一个由原字符串组成的元素。如果 separator 是一个空串,则 str 将会被分割成一个由原字符串中字符组成的数组。limit 表示从返回的数组中截取前 limit 个元素,从而限定返回的数组长度。

例子:

1
2
3
4
5
6
7
var regex = /\D/
console.log( "2017/06/26".split(regex) )
console.log( "2017.06.26".split(regex) )
console.log( "2017-06-26".split(regex) )
// => ["2017", "06", "26"]
// => ["2017", "06", "26"]
// => ["2017", "06", "26"]

3.match

定义:match() 方法用于测试字符串是否支持指定正则表达式的规则,即使传入的是非正则表达式对象,它也会隐式地使用new RegExp(obj)将其转换为正则表达式对象。

语法:str.match(regexp)

该方法返回包含匹配结果的数组,如果没有匹配项,则返回 null

匹配原则:
匹配成功就会结束,如果想继续全部匹配,加标识g

描述

  • 若正则表达式没有 g 标志,则返回同 RegExp.exec(str) 相同的结果。而且返回的数组拥有一个额外的 input 属性,该属性包含原始字符串,另外该数组还拥有一个 index 属性,该属性表示匹配字符串在原字符串中索引(从0开始)。

  • 若正则表达式包含 g 标志,则该方法返回一个包含所有匹配结果的数组,没有匹配到则返回 null。

案例:

1
2
3
4
var regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
var string = "2017-06-26";
console.log( string.match(regex) );
// =>["2017-06-26", "2017", "06", "26", index: 0, input: "2017-06-26"]

4.replace

语法:str.replace( regexp | substr, newSubStr | function[, flags] )

参数:

  • regexp: 一个 RegExp 对象. 该正则所匹配的内容会被第二个参数的返回值替换掉。
  • substr: 一个要被 newSubStr 替换的字符串.
  • newSubStr: 替换掉第一个参数在原字符串中的匹配部分. 该字符串中可以内插一些特殊的变量名.
  • function: 一个用来创建新子字符串的函数, 该函数的返回值将替换掉第一个参数匹配到的结果. 该函数的参数描-述请参考 指定一个函数作为参数 小节.
  • flags: 注意:flags 参数在 v8 内核(Chrome and NodeJs)中不起作用. 方法中使用 flags 参数不是符合标准的并且不赞成这样做.

replace后面单独写一篇文章总结

案例:

1
2
3
4
5
6
7
8
var regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
var string = "2017-06-26";
var date = [];
string.replace(regex, function(match, year, month, day) {
date.push(year, month, day);
});
console.log(date);
// => ["2017", "06", "26"]

5.test

说明:正则去匹配字符串,匹配成功,返回true,匹配失败,返回false

案例:

1
2
3
4
var regex = /\d/;
var string = "abc123";
console.log( regex.test(string) );
// => true

6.exec

说明:exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。

这个方法很类似match方法。

案例:

1
2
3
4
var regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
var string = "2017-06-26";
console.log( regex.exec(string) );
// =>["2017-06-26", "2017", "06", "26", index: 0, input: "2017-06-26"]

相关API注意要点-

1 search和match的参数问题

我们知道字符串实例的那4个方法参数都支持正则和字符串。

但search和match,会把字符串转换为正则的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var string = "2017.06.27";

console.log( string.search(".") );
// => 0
//需要修改成下列形式之一
console.log( string.search("\\.") );
console.log( string.search(/\./) );
// => 4
// => 4

console.log( string.match(".") );
// => ["2", index: 0, input: "2017.06.27"]
//需要修改成下列形式之一
console.log( string.match("\\.") );
console.log( string.match(/\./) );
// => [".", index: 4, input: "2017.06.27"]
// => [".", index: 4, input: "2017.06.27"]

console.log( string.split(".") );
// => ["2017", "06", "27"]

console.log( string.replace(".", "/") );
// => "2017/06.27"

2 match返回结果的格式问题

match返回结果的格式,与正则对象是否有修饰符g有关。

1
2
3
4
5
6
7
var string = "2017.06.27";
var regex1 = /\b(\d+)\b/;
var regex2 = /\b(\d+)\b/g;
console.log( string.match(regex1) );
console.log( string.match(regex2) );
// => ["2017", "2017", index: 0, input: "2017.06.27"]
// => ["2017", "06", "27"]

没有g,返回的是标准匹配格式,即,数组的第一个元素是整体匹配的内容,接下来是分组捕获的内容,然后是整体匹配的第一个下标,最后是输入的目标字符串。

有g,返回的是所有匹配的内容。

3 exec比match更强大

当正则没有g时,使用match返回的信息比较多。但是有g后,就没有关键的信息index了。

而exec方法就能解决这个问题,它能接着上一次匹配后继续匹配:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var string = "2017.06.27";
var regex2 = /\b(\d+)\b/g;
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
// => ["2017", "2017", index: 0, input: "2017.06.27"]
// => 4
// => ["06", "06", index: 5, input: "2017.06.27"]
// => 7
// => ["27", "27", index: 8, input: "2017.06.27"]
// => 10
// => null
// => 0

其中正则实例lastIndex属性,表示下一次匹配开始的位置。

比如第一次匹配了“2017”,开始下标是0,共4个字符,因此这次匹配结束的位置是3,下一次开始匹配的位置是4。

从上述代码看出,在使用exec时,经常需要配合使用while循环:

1
2
3
4
5
6
7
8
9
var string = "2017.06.27";
var regex2 = /\b(\d+)\b/g;
var result;
while ( result = regex2.exec(string) ) {
console.log( result, regex2.lastIndex );
}
// => ["2017", "2017", index: 0, input: "2017.06.27"] 4
// => ["06", "06", index: 5, input: "2017.06.27"] 7
// => ["27", "27", index: 8, input: "2017.06.27"] 10

4 修饰符g,对exex和test的影响

上面提到了正则实例的lastIndex属性,表示尝试匹配时,从字符串的lastIndex位开始去匹配。

字符串的四个方法,每次匹配时,都是从0开始的,即lastIndex属性始终不变。

而正则实例的两个方法exec、test,当正则是全局匹配时,每一次匹配完成后,都会修改lastIndex。下面让我们以test为例,看看你是否会迷糊:

1
2
3
4
5
6
7
var regex = /a/g;
console.log( regex.test("a"), regex.lastIndex );
console.log( regex.test("aba"), regex.lastIndex );
console.log( regex.test("ababc"), regex.lastIndex );
// => true 1
// => true 3
// => false 0

注意上面代码中的第三次调用test,因为这一次尝试匹配,开始从下标lastIndex即3位置处开始查找,自然就找不到了。

如果没有g,自然都是从字符串第0个字符处开始尝试匹配:

1
2
3
4
5
6
7
var regex = /a/;
console.log( regex.test("a"), regex.lastIndex );
console.log( regex.test("aba"), regex.lastIndex );
console.log( regex.test("ababc"), regex.lastIndex );
// => true 0
// => true 0
// => true 0

5 test整体匹配时需要使用^和$

这个相对容易理解,因为test是看目标字符串中是否有子串匹配正则,即有部分匹配即可。

如果,要整体匹配,正则前后需要添加开头和结尾:

1
2
3
4
5
6
console.log( /123/.test("a123b") );
// => true
console.log( /^123$/.test("a123b") );
// => false
console.log( /^123$/.test("123") );
// => true

6 split相关注意事项

split方法看起来不起眼,但要注意的地方有两个的。

第一,它可以有第二个参数,表示结果数组的最大长度:

1
2
3
var string = "html,css,javascript";
console.log( string.split(/,/, 2) );
// =>["html", "css"]

7 replace是很强大的


《JavaScript权威指南》认为exec是这6个API中最强大的,而我始终认为replace才是最强大的。

因为它也能拿到该拿到的信息,然后可以假借替换之名,做些其他事情。

总体来说replace有两种使用形式,这是因为它的第二个参数,可以是字符串,也可以是函数。当第二个参数是字符串时,如下的字符有特殊的含义:

$1,$2,...,$99 匹配第1~99个分组里捕获的文本
$& 匹配到的子串文本
$` 匹配到的子串的左边文本 
$' 匹配到的子串的右边文本
$$ 美元符号

例如,把”2,3,5”,变成”5=2+3”:

1
2
3
var result = "2,3,5".replace(/(\d+),(\d+),(\d+)/, "$3=$1+$2");
console.log(result);
// => "5=2+3"

又例如,把”2,3,5”,变成”222,333,555”:

1
2
3
var result = "2,3,5".replace(/(\d+)/g, "$&$&$&");
console.log(result);
// => "222,333,555"

再例如,把”2+3=5”,变成”2+3=2+3=5=5”:

1
2
3
var result = "2+3=5".replace(/=/, "$&$`$&$'$&");
console.log(result);
// => "2+3=2+3=5=5"

当第二个参数是函数时,我们需要注意该回调函数的参数具体是什么:

1
2
3
4
5
6
"1234 2345 3456".replace(/(\d)\d{2}(\d)/g, function(match, $1, $2, index, input) {
console.log([match, $1, $2, index, input]);
});
// => ["1234", "1", "4", 0, "1234 2345 3456"]
// => ["2345", "2", "5", 5, "1234 2345 3456"]
// => ["3456", "3", "6", 10, "1234 2345 3456"]

此时我们可以看到replace拿到的信息,并不比exec少。

8 使用构造函数需要注意的问题


一般不推荐使用构造函数生成正则,而应该优先使用字面量。因为用构造函数会多写很多\。

1
2
3
4
5
6
7
8
var string = "2017-06-27 2017.06.27 2017/06/27";
var regex = /\d{4}(-|\.|\/)\d{2}\1\d{2}/g;
console.log( string.match(regex) );
// => ["2017-06-27", "2017.06.27", "2017/06/27"]

regex = new RegExp("\\d{4}(-|\\.|\\/)\\d{2}\\1\\d{2}", "g");
console.log( string.match(regex) );
// => ["2017-06-27", "2017.06.27", "2017/06/27"]

9 修饰符


ES5中修饰符,共3个:

g 全局匹配,即找到所有匹配的,单词是global
i 忽略字母大小写,单词ingoreCase
m 多行匹配,只影响^和$,二者变成行的概念,即行开头和行结尾。单词是multiline

10 source属性

正则实例对象属性,除了global、ingnoreCase、multiline、lastIndex属性之外,还有一个source属性。

它什么时候有用呢?

比如,在构建动态的正则表达式时,可以通过查看该属性,来确认构建出的正则到底是什么:

1
2
3
4
var className = "high";
var regex = new RegExp("(^|\\s)" + className + "(\\s|$)");
console.log( regex.source )
// => (^|\s)high(\s|$) 即字符串"(^|\\s)high(\\s|$)"

11 构造函数属性


构造函数的静态属性基于所执行的最近一次正则操作而变化。除了是$1,…,$9之外,还有几个不太常用的属性(有兼容性问题):

RegExp.input 最近一次目标字符串,简写成RegExp["$_"]
RegExp.lastMatch 最近一次匹配的文本,简写成RegExp["$&"]
RegExp.lastParen 最近一次捕获的文本,简写成RegExp["$+"]
RegExp.leftContext 目标字符串中lastMatch之前的文本,简写成RegExp["$`"]
RegExp.rightContext 目标字符串中lastMatch之后的文本,简写成RegExp["$'"]

测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var regex = /([abc])(\d)/g;
var string = "a1b2c3d4e5";
string.match(regex);

console.log( RegExp.input );
console.log( RegExp["$_"]);
// => "a1b2c3d4e5"

console.log( RegExp.lastMatch );
console.log( RegExp["$&"] );
// => "c3"

console.log( RegExp.lastParen );
console.log( RegExp["$+"] );
// => "3"

console.log( RegExp.leftContext );
console.log( RegExp["$`"] );
// => "a1b2"

console.log( RegExp.rightContext );
console.log( RegExp["$'"] );
// => "d4e5"

结语:


我搜查列出了相关的6个方法,并对6个方法进行了说明。

后面我会对replace再单独出一篇文章。

参考资料里的第一篇文章真的非常好,值得仔细研读。

如果你想粗略了解正则的方法,看我这篇文章是没错了,后面列出的相应方法的坑点和注意点。

后面,我会再慢慢补充匹配规则,我会单独列出一篇文章,因为匹配规则也有很多注意点呢。

哈哈哈,其实也是在下面的文章里面看的啦,文章真的写得好---嘻嘻

其实正则也没有那么难的啦-----

希望这篇文章对你有帮助,每天都要加油哦。

加油,与君共勉!!!

参考资料:

文章真的写的不错,认认真真,细嚼慢咽的看完这篇文章,保证你学会正则。

这篇文章对正则的细枝末节都有详细的介绍,我摘抄了部分重要的代码,和总结了6个方法。

剩下的匹配规则、关键字等,以后会一一补充。


 评论