正则表达式是一个精巧的利器,经常用来在字符串中查找和替换,JavaScript语言参照Perl,也提供了正则表达式相关模块,开发当中非常实用,在一些类库或是框架中,比如jQuery,就存在大量的正则表达式,所以说学好正则表达式,是提高开发技能的一项基本要求。那么今天博主就来详细总结一下正则表达式的相关知识,希望不熟悉的同学们,也能够掌握正则表达式的原理及应用。

在JS中,创建正则表达式有两种方式,一种是字面量方式,一种是构造器方式,如下所示:

var regex = /\w+/;

// 或者

var regex = new RegExp('\\w+');

大家也许注意到,使用字面量要比构造器简洁得多,\w表示一个word,匹配单个字母、数字或下划线,而使用RegExp构造器时,我们的正则变为了"\\w",这是因为要在字符串中表示一个反斜杠\,我们需要对其转义,也就是在前面再加一个转义字符\。相信大家都知道,要在字面量正则中表达一个匹配反斜杠\的正则,只需写成\\这样,但在字符串中表达这个正则,则是"\\\\"这个样子的,这是因为字符串中前两个表示一个反斜杠\,后两个也表示一个反斜杠\,最终在正则层面,结果还是\\。

对于上面两种创建形式,都可以加上一些后缀修饰符,这些修饰符可以单个使用,也可以组合起来使用:

/\w+/g; // global search
/\w+/i; // ignore case
/\w+/m; // multi-line
/\w+/u; // unicode
/\w+/y; // sticky /\w+/gi;
new RegExp('\\w+', 'gi');

从英文注释来看,相信大家都大概都略知一二了,需要注意的是u和y修饰符,它们是ES6新增的特性,u表示启用Unicode模式,对于匹配中文特别有用,而y是sticky,“粘连”的意思,表示下次匹配时目标紧随当前匹配项,这个我们后面会介绍。

正则相关方法

有了正则表达式对象了,如何使用呢?JS中的正则和字符串在原型中均提供相应的方法,先来看看正则原型中的两个方法:

RegExp.prototype.test(str);
RegExp.prototype.exec(str);

上面的test()和exec()方法都需传入一个字符串,对这个字符串进行搜索和匹配,不同的是,test()方法会返回true或false,表示字符串和正则是否匹配,而exec()方法在匹配时返回一个匹配结果数组,如果不匹配,则只返回一个null值,下面来看看两者的差异:

// RegExp#test()

var regex = /hello/;
var result = regex.test('hello world'); // true // RegExp#exec() var regex = /hello/;
var result = regex.exec('hello world'); // ['hello']

对于exec()方法,如果正则中含有捕获组,匹配后则会出现在结果数组中:

// (llo)是一个捕获组

var regex = /he(llo)/;
var result = regex.exec('hello world'); // ['hello', 'llo']

开发当中,test()方法一般用于用户输入验证,比如邮箱验证,手机号验证等等,而exec()方法一般用于从特定内容中获取有价值的信息,比如从用户邮箱输入中获取其ID和邮箱类型,从手机号中获取此号码的归属地等等。

字符串相关方法

上面是正则原型中的两个方法,现在来看看字符串原型中都提供了哪些可用的方法:

String.prototype.search(regexp);
String.prototype.match(regexp);
String.prototype.split([separator[, limit]]);
String.prototype.replace(regexp|substr, newSubStr|function);

先来说说String#search()方法,它会根据正则参数对字符串进行匹配搜索,如果匹配成功,就返回第一次匹配处的索引,如果匹配失败,则返回-1。

// String#search()

'hello world'.search(/hello/);    //

'hello world'.search(/hi/);       // -1

String#match()方法跟RegExp#exec()方法相似,会返回结果数组,所不同的是,如果String#match()的正则参数中含有全局标记g,则结果中会只出现匹配的子串,而忽略捕获组,这一点与RegExp#exec()有些出入。且看下面代码:

// String#match()

'hello hello'.match(/he(llo)/);     // ['hello', 'llo']

// String#match()遇到全局g修饰符时会舍弃捕获组

'hello hello'.match(/he(llo)/g);    // ['hello', 'hello']

// RegExp#exec()仍旧包含捕获组

/he(llo)/g.exec('hello hello');     // ['hello', 'llo']

所以,如果需要总是将捕获组作为结果返回,应该使用RegExp#exec()方法,而不是String#match()方法。

接下来说说String#split()方法,这个方法用于将字符串分割,然后返回一个包含其子串的数组结果,其中separator和limit参数都是可选的,separator可指定为字符串或正则,limit指定返回结果个数的最大限制。如果separator省略,该方法的数组结果中仅包含自身源字符串;如果sparator指定一个空字符串,则源字符串将被以字符为单位进行分割;如果separator是非空字符串或正则表达式,则该方法会以此参数为单位对源字符串进行分割处理。下面代码演示了该方法的使用:

// String#split()

'hello'.split();                  // ["hello"]
'hello'.split(''); // ["h", "e", "l", "l", "o"]
'hello'.split('', 3); // ["h", "e", "l"] // 指定一个非空字符串 var source = 'hello world';
var result = source.split(' '); // ["hello", "world"] // 或者使用正则表达式 var result = source.split(/\s/); // ["hello", "world"]

如果separtor是一个正则表达式,并且正则中包含捕获组,则捕获组也会出现在结果数组中:

// String#split() 正则捕获组

var source = 'matchandsplit';

var result = source.split('and');     // ["match", "split"]

var result = source.split(/and/);     // ["match", "split"]

// 正则中含捕获组

var result = source.split(/(and)/);   // ["match", "and", "split"]

最后来介绍一下String#replace()方法,它会同时执行查找和替换两个操作。

从上面的函数签名来看,该方法会接受两个参数:第一个参数可以是一个正则表达式,也可以是一个字符串,它们都表示将要匹配的子串;第二个参数可以指定一个字符串或是一个函数,如果指定一个字符串,表示这个字符串将会替换掉已匹配到的子串,如果指定一个函数,则函数的返回值会替换掉已匹配的子串。

String#replace()方法最终会返回一个新的已经过替换的字符串。下面分别演示了replace方法的使用:

// String#replace()

var source = 'matchandsplitandreplace';

var result = source.replace('and', '-');  // "match-splitandreplace"

// 或者

var result = source.replace(/and/, function() {
return '-';
}); // "match-splitandreplace"

从上面的代码中可以看到,'and'被替换成了'-',但我们同时也注意到,只有第一个'and'被替换了,后面的并没有被处理。这里我们就需要了解,String#replace()方法只对第一次出现的匹配串进行替换,如果我们需要全局替换,需要将第一个参数指定为正则表达式,并追加全局g修饰符,就像下面这样:

// String#replace() 全局替换

var source = 'matchandsplitandreplace';

var result = source.replace(/and/g, '-'); // "match-split-replace"

var result = source.replace(/and/g, function() {
return '-';
}); // "match-split-replace"

初学者看到上面的代码,可能会觉得疑惑,对于第二个参数,直接指定一个字符串也挺简单的嘛,我们为何要使用一个函数然后再返回一个值呢。我们看看下面的例子就知道了:

// String#replace() 替换函数的参数列表

var source = 'matchandsplitandreplace';

var result = source.replace(/(a(nd))/g, function(match, p1, p2, offset, string) {

    console.group('match:');
console.log(match, p1, p2, offset, string);
console.groupEnd(); return '-';
}); // "match-split-replace"

上面代码中,第一个参数是正则表达式,其中包含了两个捕获组(and)和(nd),第二个参数指定一个匿名函数,其函数列表中有一些参数:match, p1, p2, offset, string,分别对应匹配到的子串、第一个捕获组、第二个捕获组、匹配子串在源字符串中的索引、源字符串,我们可以称这个匿名函数为“replacer”或“替换函数”,在替换函数的参数列表中,match、offset和string在每一次匹配时总是存在的,而中间的p1、p2等捕获组,String#replace()方法会根据实际匹配情况去填充,当然,我们还可以根据arguments获取到这些参数值。

下面是代码运行后的控制台打印结果:

现在来看,指定一个函数要比指定一个字符串功能强的多,每次匹配都能获取到这些有用的信息,我们可以对其进行一些操作处理,最后再返回一个值,作为要替换的新子串。所以推荐在调用String#replace()方法时,使用上面这种方式。

上面是String类与正则相关的常用方法,需要注意的是,String#search()和String#match()方法签名中参数均为正则对象,如果我们传递了其他类型的参数,会被隐式转换为正则对象,具体的步骤是先调用参数值的toString()方法得到字符串类型的值,然后调用new RegExp(val)得到正则对象:

// -> String#search(new RegExp(val.toString()))

'123 123'.search(1);        //
'true false'.search(true); // '123 123'.search('\\s'); // var o = {
toString: function() {
return '\\s';
}
};
'123 123'.search(o); // // -> String#match(new RegExp(val.toString())) '123 123'.match(1); // ["1"]
'true false'.match(true); // ["true"] '123 123'.match('\\s'); // [" "] var o = {
toString: function() {
return '1(23)';
}
};
'123 123'.match(o); // ["123", "23"]

而split()和replace()方法不会将字符串转为正则表达式对象,对于其他类型值,只会调用其toString()方法将参数值转为字符串,也不会进一步向正则转换,大家可以亲自测试一下。

以上就是正则的相关基本知识及常用方法,限于篇幅原因,更多关于正则表达式的内容,博主会安排在下一篇中介绍和讲解,敬请期待。

参考资料:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

http://es6.ruanyifeng.com/#docs/regex

JavaScript系列文章:详解正则表达式之一的更多相关文章

  1. 【HANA系列】SAP HANA XS使用JavaScript数据交互详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Jav ...

  2. 【HANA系列】【第一篇】SAP HANA XS使用JavaScript数据交互详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第一篇]SAP HANA XS ...

  3. 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程

    反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑)   背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...

  4. 从mixin到new和prototype:Javascript原型机制详解

    从mixin到new和prototype:Javascript原型机制详解   这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...

  5. [转]JavaScript异步机制详解

    原文: https://www.jianshu.com/p/4ea4ee713ead --------------------------------------------------------- ...

  6. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT Source Maps 详解

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  7. JavaScript严格模式详解

    转载自阮一峰的博客 Javascript 严格模式详解   作者: 阮一峰 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict m ...

  8. [转]javascript console 函数详解 js开发调试的利器

    javascript console 函数详解 js开发调试的利器   分步阅读 Console 是用于显示 JS和 DOM 对象信息的单独窗口.并且向 JS 中注入1个 console 对象,使用该 ...

  9. javascript 节点属性详解

    javascript 节点属性详解 根据 DOM,html 文档中的每个成分都是一个节点 DOM 是这样规定的:整个文档是一个文档节点每个 html 标签是一个元素节点包含在于 html 元素中的文本 ...

  10. (" use strict")Javascript 严格模式详解

    Javascript 严格模式详解 转载别人的博客内容,浏览了一遍,没有全部吸收,先保存一下链接 http://www.ruanyifeng.com/blog/2013/01/javascript_s ...

随机推荐

  1. node.js xtemplate的使用实例

    工程下安装XTemplate并使用它的方法实例说明: 1.安装xtpl npm install xtpl xtemplate --save 2.在views目录添加test.xtpl文件,其内容为 t ...

  2. DevExpress v16.1.5图表、Dashboard等多个控件API发生变化

    Dashboard # BC3835: WinForms Dashboard Designer - ChartSeriesTypeGalleryItem bar item停用 在v16.1.5之前,D ...

  3. Android将应用调试log信息保存在SD卡

    转载:http://blog.csdn.net/way_ping_li/article/details/8487866 把自己应用的调试信息写入到SD卡中. package com.sdmc.hote ...

  4. Cell右滑 多个编辑选项栏

    简单粗暴,一看就能明白 关于右滑cell,能滑出来两个以上的选项栏,可以如下这么做,但是要注意下面的注意事项,就是关于iOS8前后的问题,注释写的很清楚了.可以直接复制到自己的代码里看的会更明白. / ...

  5. 安装cocoapods以及更新cocoapods

    安装 1.设置ruby的软件源 这是因为ruby的软件源rubygems.org因为使用亚马逊的云服务,被我天朝屏蔽了,需要更新一下ruby的源,过程如下: gem sources -l #(查看当前 ...

  6. Ubuntu搭建NFS

    NFS全称是Network File System,网络文件系统.它可以通过网络实现文件共享.其结构图大概是这样的: 在机器E上开启NFS服务,机器ABCD都挂载NFS,这样可以实现机器ABCD共享文 ...

  7. yii2 RESTful api的详细使用

    作者:白狼 出处:http://www.manks.top/yii2-restful-api.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则 ...

  8. 原创 C++应用程序在Windows下的编译、链接:第二部分COFF/PE文件结构

    2.1概述 在windows操作系统下,可执行文件的存储格式是PE格式:在Linux操作系统下,可执行文件的存储格式的WLF格式.它们都是COFF格式文件的变种,都是从COFF格式的文件演化而来的. ...

  9. PostgreSQL-PL/pgSQL-cursor,loop

    将spam_keyword表word字段的字符全部拆分,只是利用过程语言完成循环的操作而已. create or replace function proc1() returns setof text ...

  10. nginx整理

    一.为什么选择Nginx搭建Web服务器 Apache和Nginx是目前使用最火的两种Web服务器,Apache出现比Nginx早.Apache HTTP Server(简称Apache)是世界使用排 ...