JavaScript之RegExp_动力节点Java学院整理


Posted in Javascript onJune 29, 2017

字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以复用。

正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。

所以我们判断一个字符串是否是合法的Email的方法是:

1.创建一个匹配Email的正则表达式;

2.用该正则表达式去匹配用户的输入来判断是否合法。

因为正则表达式也是用字符串表示的,所以,我们要首先了解如何用字符来描述字符。

在正则表达式中,如果直接给出字符,就是精确匹配。用\d可以匹配一个数字,\w可以匹配一个字母或数字,所以:

  • '00\d'可以匹配'007',但无法匹配'00A';
  • '\d\d\d'可以匹配'010';
  • '\w\w'可以匹配'js';

.可以匹配任意字符,所以:

  • 'js.'可以匹配'jsp'、'jss'、'js!'等等。

要匹配变长的字符,在正则表达式中,用*表示任意个字符(包括0个),用+表示至少一个字符,用?表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n-m个字符:

来看一个复杂的例子:\d{3}\s+\d{3,8}

我们来从左到右解读一下:

1.\d{3}表示匹配3个数字,例如'010';

2.\s可以匹配一个空格(也包括Tab等空白符),所以\s+表示至少有一个空格,例如匹配' ','\t\t'等;

3.\d{3,8}表示3-8个数字,例如'1234567'。

综合起来,上面的正则表达式可以匹配以任意个空格隔开的带区号的电话号码。

如果要匹配'010-12345'这样的号码呢?由于'-'是特殊字符,在正则表达式中,要用'\'转义,所以,上面的正则是\d{3}\-\d{3,8}。

但是,仍然无法匹配'010 - 12345',因为带有空格。所以我们需要更复杂的匹配方式。

进阶

要做更精确地匹配,可以用[]表示范围,比如:

  • [0-9a-zA-Z\_]可以匹配一个数字、字母或者下划线;
  • [0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'a100','0_Z','js2015'等等;
  • [a-zA-Z\_\$][0-9a-zA-Z\_\$]*可以匹配由字母或下划线、$开头,后接任意个由一个数字、字母或者下划线、$组成的字符串,也就是JavaScript允许的变量名;
  • [a-zA-Z\_\$][0-9a-zA-Z\_\$]{0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)。

A|B可以匹配A或B,所以(J|j)ava(S|s)cript可以匹配'JavaScript'、'Javascript'、'javaScript'或者'javascript'。

^表示行的开头,^\d表示必须以数字开头。

$表示行的结束,\d$表示必须以数字结束。

你可能注意到了,js也可以匹配'jsp',但是加上^js$就变成了整行匹配,就只能匹配'js'了。

RegExp

有了准备知识,我们就可以在JavaScript中使用正则表达式了。

JavaScript有两种方式创建一个正则表达式:

第一种方式是直接通过/正则表达式/写出来,第二种方式是通过new RegExp('正则表达式')创建一个RegExp对象。

两种写法是一样的:

var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');
re1; // /ABC\-001/
re2; // /ABC\-001/

注意,如果使用第二种写法,因为字符串的转义问题,字符串的两个\\实际上是一个\。

先看看如何判断正则表达式是否匹配:

var re = /^\d{3}\-\d{3,8}$/;
re.test('010-12345'); // true
re.test('010-1234x'); // false
re.test('010 12345'); // false

RegExp对象的test()方法用于测试给定的字符串是否符合条件。

切分字符串

用正则表达式切分字符串比用固定的字符更灵活,请看正常的切分代码:

'a b  c'.split(' '); // ['a', 'b', '', '', 'c']

嗯,无法识别连续的空格,用正则表达式试试:

'a b  c'.split(/\s+/); // ['a', 'b', 'c']

无论多少个空格都可以正常分割。加入,试试:

'a,b, c d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']

再加入;试试:

'a,b;; c d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']

如果用户输入了一组标签,下次记得用正则表达式来把不规范的输入转化成正确的数组。

分组

除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(Group)。比如:

^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:

var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
re.exec('010 12345'); // null

如果正则表达式中定义了组,就可以在RegExp对象上用exec()方法提取出子串来。

exec()方法在匹配成功后,会返回一个Array,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串。

exec()方法在匹配失败时返回null。

提取子串非常有用。来看一个更凶残的例子:

var re = /^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$/;
re.exec('19:05:30'); // ['19:05:30', '19', '05', '30']

这个正则表达式可以直接识别合法的时间。但是有些时候,用正则表达式也无法做到完全验证,比如识别日期:

var re = /^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$/;

对于'2-30','4-31'这样的非法日期,用正则还是识别不了,或者说写出来非常困难,这时就需要程序配合识别了。

贪婪匹配

需要特别指出的是,正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。举例如下,匹配出数字后面的0:

var re = /^(\d+)(0*)$/;
re.exec('102300'); // ['102300', '102300', '']

由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串了。

必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:

var re = /^(\d+?)(0*)$/;
re.exec('102300'); // ['102300', '1023', '00']

全局搜索

JavaScript的正则表达式还有几个特殊的标志,最常用的是g,表示全局匹配:

var r1 = /test/g;
// 等价于:
var r2 = new RegExp('test', 'g');

全局匹配可以多次执行exec()方法来搜索一个匹配的字符串。当我们指定g标志后,每次运行exec(),正则表达式本身会更新lastIndex属性,表示上次匹配到的最后索引:

var s = 'JavaScript, VBScript, JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;
// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10
re.exec(s); // ['VBScript']
re.lastIndex; // 20
re.exec(s); // ['JScript']
re.lastIndex; // 29
re.exec(s); // ['ECMAScript']
re.lastIndex; // 44
re.exec(s); // null,直到结束仍没有匹配到

全局匹配类似搜索,因此不能使用/^...$/,那样只会最多匹配一次。

正则表达式还可以指定i标志,表示忽略大小写,m标志,表示执行多行匹配。

小结

正则表达式非常强大,要在短短的一节里讲完是不可能的。要讲清楚正则的所有内容,可以写一本厚厚的书了。如果你经常遇到正则表达式的问题,你可能需要一本正则表达式的参考书。

练习

请尝试写一个验证Email地址的正则表达式。版本一应该可以验证出类似的Email:

Javascript 相关文章推荐
基于jQuery的倒计时插件代码
May 07 Javascript
Javascript 类、命名空间、代码组织代码
Jul 31 Javascript
JS验证身份证有效性示例
Oct 11 Javascript
Javascript常用字符串判断函数代码分享
Dec 08 Javascript
js+CSS实现弹出居中背景半透明div层的方法
Feb 26 Javascript
值得分享的轻量级Bootstrap Table表格插件
May 30 Javascript
把json格式的字符串转换成javascript对象或数组的方法总结
Nov 03 Javascript
微信小程序 css使用技巧总结
Jan 09 Javascript
jquery 禁止鼠标右键并监听右键事件
Apr 27 jQuery
实例详解带参数的 npm script
May 28 Javascript
jQuery实现二级导航菜单的示例
Sep 30 jQuery
解决await在forEach中不起作用的问题
Feb 25 Javascript
详解微信小程序设置底部导航栏目方法
Jun 29 #Javascript
详解vue2父组件传递props异步数据到子组件的问题
Jun 29 #Javascript
Vue.js列表渲染绑定jQuery插件的正确姿势
Jun 29 #jQuery
详解vue父子组件间传值(props)
Jun 29 #Javascript
详解如何使用Node.js编写命令工具——以vue-cli为例
Jun 29 #Javascript
基于angular2 的 http服务封装的实例代码
Jun 29 #Javascript
JS通过调用微信API实现微信支付功能的方法示例
Jun 29 #Javascript
You might like
zend framework多模块多布局配置
2011/02/26 PHP
PHP使用CURL模拟登录的方法
2015/07/08 PHP
php函数mkdir实现递归创建层级目录
2016/10/27 PHP
thinkPHP5框架自定义验证器实现方法分析
2018/06/11 PHP
PHP基于mcript扩展实现对称加密功能示例
2019/02/21 PHP
Laravel框架之解决前端显示图片问题
2019/10/24 PHP
JavaScript入门教程(12) js对象化编程
2009/01/31 Javascript
js 巧妙去除数组中的重复项
2010/01/25 Javascript
javascript字符串拼接的效率问题
2010/12/25 Javascript
JavaScript中的细节分析
2012/06/30 Javascript
javascript中sort()的用法实例分析
2015/01/30 Javascript
jQuery多级手风琴菜单实例讲解
2015/10/22 Javascript
快速学习AngularJs HTTP响应拦截器
2015/12/31 Javascript
jQuery中借助deferred来请求及判断AJAX加载的实例讲解
2016/05/24 Javascript
jQuery实现iframe父窗体和子窗体的相互调用
2016/06/17 Javascript
HTML5 实现的一个俄罗斯方块实例代码
2016/09/19 Javascript
Bootstrap 模态对话框只加载一次 remote 数据的完美解决办法
2017/07/09 Javascript
前端把html表格生成为excel表格的实例
2017/09/19 Javascript
微信小程序ibeacon三点定位详解
2018/10/31 Javascript
详解nuxt路由鉴权(express模板)
2018/11/21 Javascript
vue-cli3 引入 font-awesome的操作
2020/08/11 Javascript
vantUI 获得piker选中值的自定义ID操作
2020/11/04 Javascript
基于vue项目设置resolves.alias: '@'路径并适配webstorm
2020/12/02 Vue.js
举例简单讲解Python中的数据存储模块shelve的用法
2016/03/03 Python
python探索之BaseHTTPServer-实现Web服务器介绍
2017/10/28 Python
Django model反向关联名称的方法
2018/12/15 Python
画pytorch模型图,以及参数计算的方法
2019/08/17 Python
Python创建一个元素都为0的列表实例
2019/11/28 Python
纯CSS3打造属于自己的“小黄人”
2016/03/14 HTML / CSS
利用css3径向渐变做一张优惠券的示例
2018/03/22 HTML / CSS
HTML5 Notification(桌面提醒)功能使用实例
2014/03/17 HTML / CSS
英语专业毕业生自我鉴定
2013/11/09 职场文书
2016年大学自主招生自荐信范文
2015/03/24 职场文书
幼儿园小班班务总结
2015/08/03 职场文书
护理工作心得体会
2016/01/22 职场文书
PHP面试题 wakeup魔法 Ezpop pop序列化与反序列化
2022/04/11 PHP