资讯专栏INFORMATION COLUMN

JavaScript正则表达式RegExp

SexySix / 1302人阅读

摘要:的正则表达式体系是参照建立的。字面量形式构造函数形式以上都是创建了一个内容为的正则表达式,其表示对一个手机号码的校验。按照给定的正则表达式进行替换,返回替换后的字符串。

正则表达式,也称规则表达式,经常使用其来完成对字符串的校验和过滤。由于正则表达式的灵活性、逻辑性和功能性都非常强大,而且 可以利用很简单的方式完成对复杂字符串的控制,所以很多程序语言都支持正则表达式。在JavaScript中正则表示也非常强大和实用。

基本形式

正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符串的模板,常常用作按照“给定模式”匹配文本的工具。比如,正则表达式给出一个Email地址的模式,然后用它来确定一个字符串是否为Email地址。JavaScript的正则表达式体系是参照Perl 5建立的。

新建正则表达式有两种方法。一种是使用字面量,以斜杠表示开始和结束。

// 字面量形式
var telRegex1 = /^1[3|5|7|8]d{9}$/;
// 构造函数形式
var telRegex2 = new RegExp("^1[3|5|7|8]d{9}$");

以上都是创建了一个内容为^1[3|5|7|8]d{9}$的正则表达式,其表示对一个手机号码的校验。必须以1开始,第二位为3/5/7/8,之后为9位数字。

这两种写法——字面量和构造函数——在运行时有一个细微的区别。采用字面量的写法,正则对象在代码载入时(即编译时)生成;采用构造函数的方法,正则对象在代码运行时生成。考虑到书写的便利和直观,实际应用中,基本上都采用字面量的写法。

有一点需要注意,使用构造函数创建正则表达式时,传入的参数是字符串形式的,在字符串内部,本身也是一个转义符,因此需要再使用一个来对其进行正则表达式的转义。上面第二个示例中,d才能代表任意数字。

关于正则表达式中,各种符号的含义,以及使用方法,请看后面的介绍:

元字符

一些常用的元字符如下:

. 匹配除换行符之外的任意字符

w 匹配字母或数字或下划线或汉字

s 匹配任意的空白符

d 匹配数字

 匹配单词的开始或结束

^ 匹配字符串的开始处

$ 匹配字符串的结束处。

* 匹配前面的子表达式任意次。

? 匹配前面子表达式0次或一次,等价于{0, 1}

+ 匹配之前子表达式一次到多次,等价于{1, }

{n} 匹配之前的子表达式n次。

{m,n} 匹配之前的子表达式最少m次,最多n次。

{n, } 匹配之前的子表达式至少n次。

[xyz] 字符集合,表示其中任意一个字符。表示范围可用-链接,例如[a-z] 表示a-z之间的任意一个字母。还可以这样书写[A-Za-z0-9]

[^xyz] 字符即可,表示非其中任意一个字符。表示范围可用-链接,例如[^a-z] 表示非 a-z之间的任意一个字母。

| 表示或(or)关系,例如 com|cn,表示匹配com或者cn。

() 用于分组,其分组中的内容可已通过$1-$9按顺序获取(字符串相关方法中),之后的正则中也可以通过1-9进行引用(正则表达式内部)。(分组0表示整个正则匹配内容或整个正则表达式)

在正则表达式中,以上这些以及一些未列出的元字符都是有自身含义的,如果我们需要匹配这些元字符本身,可以使用对其进行转义即可。

更多元字符可以查看:正则表达式

属性 修饰符

ignoreCase:返回一个布尔值,表示是否设置了i修饰符,该属性只读。

global:返回一个布尔值,表示是否设置了g修饰符,该属性只读。

multiline:返回一个布尔值,表示是否设置了m修饰符,该属性只读。

stickyES6返回一个布尔值,表示是否设置了y修饰符,只读。

var r = /abc/igm;

r.ignoreCase; // true
r.global;  // true
r.multiline;  // true
匹配时属性

lastIndex:返回下一次开始搜索的位置。该属性可读写,但是只在设置了g修饰符时有意义。

sourceES5返回正则表达式的字符串形式(不包括反斜杠),该属性只读。

flagsES6返回正则表达式中的修饰符。

var r = /abc/igm;

r.lastIndex; // 0
r.source; // "abc"
r.flags; //"igm"
方法 test()

正则对象的test对象接收一个字符串,表示测试字符串,返回一个布尔值,表示是此字符串是否满足匹配条件。

telRegex1.test("13612341234"); // true
telRegex2.test("13612341234"); // true
telRegex1.test("136123412"); // false

如果正则表达式带有g修饰符,则每一次test方法都从上一次结束的位置开始向后匹配。同时,可以通过正则对象的lastIndex属性指定开始搜索的位置。

var xReg = /x/g;
var str = "xyz_x1_y1_x3";

xReg.lastIndex; // 0
xReg.test(str); // true

xReg.lastIndex; // 1
xReg.test(str); // true
xReg.lastIndex; // 5

// 指定位置开始 指定下次匹配从最后一位开始,就匹配不到了
xReg.lastIndex = 11; // 11
xReg.test(str); // false

xReg.lastIndex; // 0
var indexReg = /^(?:http|https).+/jwebui/pages/themes/(w+)/1.jspx(?S+)?$/i ;

上面是一个F8中检查是否为首页的正则表达式。

最开始的^ 和最后的$分别表示匹配的开始和结束。

(?:http|https)表示两者之一,这么写是非获取的组匹配,()不会被分组存储。也可以写成(http|https) 但是后面的1就需要替换成2了,因为这么写时此处形成了第一个分组。

.+ 就是任意字符至少出现一次。

/jwebui/pages/themes/ 就是匹配字符串"/jwebui/pages/themes/"

(w+) 作为第一个分组,表示任意字母或数字或下划线或汉字至少出现一次。

1表示对第一个分组的引用,再重复第一分组的内容 。

.jspx 表示.jspx

(?S+)? 表示(?S+) 匹配的内容出现0次或一次。其中:

? 表示

S+ 表示任意可见字符出现至少一次。
`

exec()

正则对象的exec方法,可以返回匹配结果。如果发现匹配,就返回一个数组,成员是每一个匹配成功的子字符串,否则返回null

如果正则表示式包含圆括号(即含有“组匹配”),则返回的数组会包括多个成员。第一个成员是整个匹配成功的结果,后面的成员就是圆括号对应的匹配成功的组。也就是说,第二个成员对应第一个括号,第三个成员对应第二个括号,以此类推。整个数组的length属性等于组匹配的数量再加1。

var ipReg = /(d{1,3}.){3}(d{1,3})/;
var ipStr = "My ip is "192.168.118.47" , please tell me yours";

ipReg.exec(ipStr); // ["192.168.118.47", "118.", "47"]

上面第一段代码表示一个简单的IP检验,数字的1-3位之后紧跟一个.,接着这个整体要出现3次,最后再有一段数字的1-3位。结果数组中,第一个值表示匹配到的结果,之后的表示正则分组匹配到的内容。

如果正则表达式加上g修饰符,则可以使用多次exec方法,下一次搜索的位置从上一次匹配成功结束的位置开始。同时还可以指定lastIndex,使之下次从指定位置开始(可见之前的test示例)。

var ipLastReg = /d+(?=;)/g;

var ipsStr = "192.168.118.47;192.168.118.46;192.168.118.48;";

ipLastReg.exec(ipsStr); // ["47"]
ipLastReg.exec(ipsStr); // ["46"]
ipLastReg.exec(ipsStr); // ["48"]

上面代码中正则中的(?=;)表示先行断言,表示只匹配在;前面d+

如果只是为了得到是否匹配,请使用 RegExp.test()方法或字符串实例的.search() 替代,效率更高。

字符串相关方法

之所以称之为字符串相关方法是因为其是在字符串上调用的(虽然ES6开始,内部调用的是正则上的方法,但还是在字符串上提供的入口)。

match():返回一个数组,成员是所有匹配的子字符串。

search():按照给定的正则表达式进行搜索,返回一个整数,表示匹配开始的位置。

replace():按照给定的正则表达式进行替换,返回替换后的字符串。

split():按照给定规则进行字符串分割,返回一个数组,包含分割后的各个成员。

match()

match方法对字符串进行正则匹配,返回匹配结果。此方法方法与正则对象的exec方法非常类似:匹配成功返回一个数组,匹配失败返回null。如果正则表达式带有g修饰符,则该方法与正则对象的exec方法行为不同,会一次性返回所有匹配成功的结果。

var ipLastReg = /d+(?=;)/g;
var ipsStr = "192.168.118.47;192.168.118.46;192.168.118.48;";

ipsStr.match(ipLastReg); // ["47", "46", "48"]

上面的正则是匹配IP中的最后一位,其中使用了(?=;)意为先行断言,表示只匹配在;之前的内容,但是不包括;。关于更多先行断言,请看下文。

search()

search方法,返回第一个满足条件的匹配结果(可直接使用字符串,不一定是正则对象)在整个字符串中的位置。如果没有任何匹配,则返回-1

var nowDateStr = "2016-11-1";
var testReg = /-/g;

nowDateStr.search(testReg); // 4
// 再次查找还是4
nowDateStr.search(testReg); // 4

//  检查lastIndex 并设置 
testReg.lastIndex; // 0
testReg.lastIndex = 6;
nowDateStr.search(testReg); // 4  结果仍为4

search方法总是从字符串的开始位置查找,与正则表达式的g修饰符和lastIndex属性无关。

replace()

replace方法可以替换匹配的值,返回替换后的新字符串。它接受两个参数,第一个是搜索模式(可直接使用字符串,不一定是正则对象),第二个是替换的内容(可使用字符串或一个函数)。搜索模式如果不加g修饰符,就替换第一个匹配成功的值,否则替换所有匹配成功的值。

其中replace方法的第二个参数可以使用美元符号$,用来指代所替换的内容,具体如下所示:

$& 指代匹配的子字符串。

$` 指代匹配结果前面的文本。

$" 指代匹配结果后面的文本。

$n 指代匹配成功的第n组内容,n是从1开始的自然数。

$$ 指代美元符号$。

var re = /-/g; 
var str = "2016-11-01";
var newstr = str.replace(re,".");
console.log(newstr);  // "2016.11.01"

"hello world".replace(/(w+)s(w+)/, "$2 $1");
// "world hello"

"abc".replace("b", "[$`-$&-$"]");
// "a[a-b-c]c"

第二个参数为函数:

function toCamelStyle(str) {
    // 匹配-以及之后的一个字符,其中这个字符在一个分组内
    var camelRegExp = /-([a-z])/ig;

    return str.replace(camelRegExp, function(all, letter) {
        // all为匹配到的内容,letter为组匹配        
        return letter.toUpperCase();
    });
}

toCamelStyle("margin-left"); // "marginLeft"
toCamelStyle("aa-bb-cccc"); // "aaBbCccc"

以上代码展示通过正则将aa-bb-cccc这样的字符串转化为aaBbCccc 这种形式。replace回调函数接收两个参数,第一个为匹配到的内容,第二个为匹配到的分组,有多少组就可以传多少个参数,在此之后还可以有两个参数,一个为匹配到内容在原字符串的位置,另一个是原字符串。

split()

split方法按照正则规则分割字符串,返回一个由分割后的各个部分组成的数组。该方法接受两个参数,第一个参数是分隔规则(可直接使用字符串,不一定是正则对象),第二个参数是返回数组的最大成员数。

"2016-11-01".split("-"); // ["2016", "11", "01"]
"2016-11-01".split(/-/); // ["2016", "11", "01"]
贪婪模式和懒惰模式

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符,称之为贪婪模式

例如:

var s = "aaa";
s.match(/a+/); // ["aaa"]

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。

var s = "aaa";
s.match(/a+?/); // ["a"]

以下是一些说明

*? 重复任意次,但尽可能少重复

+? 重复1次或更多次,但尽可能少重复

?? 重复0次或1次,但尽可能少重复

{n,m}? 重复n到m次,但尽可能少重复

{n,}? 重复n次以上,但尽可能少重复

也就是说默认情况下,都是贪婪模式,加上一个时就转化为了懒惰模式,也称非贪婪模式。

组匹配

通常一个()中的内容就构成了一个分组,此分组内容将被存储,可在之后的正则表达式(使用1-9)和相关方法中(使用 $1-$9)引用,前面已经介绍过了,就不再说了。

关于组匹配,还有以下几种情况:

非捕获组

(?:x) 称为非捕获组(Non-capturing group),表示不返回该组匹配的内容,即匹配的结果中不计入这个括号。

// 正常匹配
var url = /(http|ftp)://([^/
]+)(/[^
]*)?/;

url.exec("http://google.com/");
// ["http://google.com/", "http", "google.com", "/"]

// 非捕获组匹配
var url = /(?:http|ftp)://([^/
]+)(/[^
]*)?/;

url.exec("http://google.com/");
// ["http://google.com/", "google.com", "/"]

之后先行断言先行否定断言也都是非捕获组

先行断言

x(?=y)称为先行断言(Positive look-ahead),x只有在y前面才匹配,y不会被计入返回结果。

比如之前匹配ip的例子:

var ipLastReg = /d+(?=;)/g;
var ipsStr = "192.168.118.47;192.168.118.46;192.168.118.48;";

ipsStr.match(ipLastReg); // ["47", "46", "48"]

上面正则对象中(?=;)就表示只匹配在;之前的内容,但是不包括;

先行否定断言

x(?!y)称为先行否定断言(Negative look-ahead),x只有不在y前面才匹配,y不会被计入返回结果。

var xreg = /d+(?!%)/g ;
xreg.exec("100% is 1"); // ["10"]
xreg.exec("100% is 1"); // ["1"]
/d+?(?!%)/.exec("100% is 1"); // ["1"]

上面代码表示匹配不在%前的数字,xreg中直接书写的d+ 表示贪婪模式,因此第一次匹配到的是10,第二次才会匹配到后面的1,因为作为数字10本身也不在%前面,正则不会将100当成一个整体(注意:这里需要定义一个正则对象来调用,直接以字面量形式的正则调用时,每次调用都是一个新对象,结果始终是10)。

为了一次匹配到最后的1,我们在d+之后加一个?将其转为非贪婪模式即可。

为了一次匹配到前面100中的1,我们在d+之后加一个?将其转为非贪婪模式即可。

ES6之前,JavaScript中不支持后行断言否定后行断言,ES6中添加了对此的支持,请看之后的ES扩展部分。

ES6扩展 构造函数

RegExp构造函数的参数有两种情况。

第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。

第二种情况是,参数是一个正则表示式,此时不能有第二个参数,会返回一个原有正则表达式的拷贝。

ES6 针对第二种情况,允许传入第二个参数,用于设置第一个参数正则表达式的修饰符。

var regex = new RegExp(/xyz/, "i"); // ES6之前 语法错误

new RegExp(/abc/ig, "i"); // ES6中结果为: /abc/i  
字符串的正则方法

字符串对象共有4个方法,可以使用正则表达式:match()replace()search()split()

ES6将这4个方法,在语言内部全部调用RegExp的实例方法,从而做到所有与正则相关的方法,全都定义在RegExp对象上。

修饰符

ES6对正则表达式添加了u修饰符,含义为“Unicode模式”,用来正确处理大于uFFFF的Unicode字符。也就是说,会正确处理四个字节的UTF-16编码。

ES6还为正则表达式添加了y修饰符,叫做“粘连”(sticky)修饰符。

y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。

var s = "aaa_aa_a";
var r1 = /a+/g;
var r2 = /a+/y;

// 第一次都能正确匹配
r1.exec(s); // ["aaa"]
r2.exec(s); // ["aaa"]

// 第二次结果就不一致了
r1.exec(s); // ["aa"]
r2.exec(s); // null

个人理解,y是类似于在每次匹配时隐式地添加了^,表示开始位置。

属性

ES5中,正则对象存在source属性,用于返回正则表达式本身。

ES6中,又添加了flags属性,用于返回正则对象的所有修饰符。

后行断言

后行断言于先行断言相反。例如/(?<=y)x/ 表示匹配x,但是要求x必须在y后面。

同理 后行否定断言则为:/(? 表示匹配x,但是要求x不能在y后面。

需要注意的是,存在后行断言时,正则执行顺序发生了改变,会先匹配后行断言的这部分,再匹配其他的的,顺序变成了从右向左。因此一些匹配操作的结果可能大不一致,而且正则中的1-9的引用顺序也会发生变化。

参考链接

ES6入门 - 正则表达式

JavaScript RegExp

正则表达式30分钟入门教程

原文发表在我的博客JavaScript正则表达式RegExp,欢迎访问!

错误修正

先行否定断言中

为了一次匹配到最后的1,我们在d+之后加一个?将其转为非贪婪模式即可。

为了一次匹配到前面100中的1,我们在d+之后加一个?将其转为非贪婪模式即可。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82169.html

相关文章

  • JS中的正则达式

    摘要:构造函数可以有两个字符串参数,第一个参数包含正则表达式的主体部分。只读的布尔值,说明这个正则表达式是否带有修饰符。中正则的扩展构造函数在中,只能接受字符串作为参数,允许其直接接受正则表达式作为参数。 上文传送门:初探正则表达式 正则表达式是一个描述字符模式的对象,JavaScript 的 RegExp 类表示正则表达式,String 和 RegExp 都定义了方法,后者使用正则表达式进...

    Soarkey 评论0 收藏0
  • JavaScript正则达式的匹配模式

    摘要:选择分组和引用正则表达式的语法还包括指定选择项子表达式分组和引用前一子表达式的特殊字符。带圆括号的表达式的另一个用途是允许在同一正则表达式的后部引用前面的子表达式。 正则表达式(regular expression)是一个描述字符模式的对象。JavaScript的 RegExp类 表示正则表达式,String和RegExp都定义了方法,后者使用正则表达式进 行强大的模式匹配和文本检索与...

    wqj97 评论0 收藏0
  • JavaScript 闯关记》之正则达式

    摘要:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。其中,表示匹配项在字符串中的位置,而表示应用正则表达式的字符串。下面列出了正则表达式所不支持的特性。关卡按要求完成下列常用的正则表达式。 由于本课程的核心是 JavaScript,所以本文着重讲解了「正则表达式」在 JavaScript 中的用法,并未深入「正则表达式」的具体细节。如果您尚不了解「正则表达式」,强...

    TalkingData 评论0 收藏0
  • JavaScript标准库系列——RegExp对象(三)

    摘要:目录导语理解正则表达式模式的规则字符串和正则实例的属性和方法检索实例小结导语正则表达式是处理字符串的一门艺术手法,应用场景经常出现在表单验证部分高级程序设计一书开篇提到,这门语言最原始的应用就是处理输入验证操作,所以正则表达式从诞生那一刻就 目录 导语 1.理解正则表达式 2.模式的规则 3.字符串和正则实例的属性和方法 4.检索实例 5. 小结 导语 正则表达式是处理字符串的一门艺...

    邱勇 评论0 收藏0
  • JavaScript面向对象编程——RegExp类型

    摘要:由于某些字符类非常常用,的正则表达式中,使用特殊转义字符表示他们。多行搜索代码示例对象创建对象可以通过引用类型创建正则表达式对象参数参数被称为模式,可以使任何简单或复杂的正则表达式,包含字符类限定符分组向前查找以及反向引用等。 概述 正则表达式是什么 正则表达式(RegularExpression):由一些普通字符和特殊字符组成的,用以描述一种特定的字符规则的表达式。正则表达式常用在一...

    Magicer 评论0 收藏0
  • JavaScript中的正则达式

    Javascript的正则表达式是前端中比较重要的部分,正则表达式主要用于字符串处理,表单验证等场合,实用高效,文章主要对JavaScript中的正则的学习与总结 正则表达式的定义 正则表达式:是一个描述字符模式的对象,JavaScrip中正则表达式用RegExp对象表示,可以使用RegExp构造函数来创建正则对象 正则表达式的创建 1.字面量创建 var reg = /[a-z]/; 2.构...

    _Zhao 评论0 收藏0

发表评论

0条评论

SexySix

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<