jQuery源码分析-02正则表达式 RegExp 常用正则表达式


Posted in Javascript onNovember 14, 2011

作者:nuysoft/JS攻城师/高云 QQ:47214707 EMail:nuysoft@gmail.com
声明:本文为原创文章,如需转载,请注明来源并保留原文链接。
后文预告:jQuery中的正则表达式分析

2.4 常用正则表达式
在网上找到一篇广为流传的文章《常用正则表达式》,逐一分析,不足地方进行补充和纠正。

常用的数字正则(严格匹配) 
正则 含义 
^[1-9]\d*$ 匹配正整数 
^-[1-9]\d*$ 匹配负整数 
^-?[1-9]\d*$ 匹配整数 
^[1-9]\d*|0$ 匹配非负整数(正整数 + 0) 
^-[1-9]\d*|0$ 匹配非正整数(负整数 + 0) 
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 匹配正浮点数 
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 匹配负浮点数 
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ 匹配浮点数 
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ 匹配非负浮点数(正浮点数 + 0) 
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ 匹配非正浮点数(负浮点数 + 0)

常用字符串正则 正则 含义 补充 
^[A-Za-z]+$ 匹配由26个英文字母组成的字符串 或 /^[a-z]+$/i 
^[A-Z]+$ 匹配由26个英文字母的大写组成的字符串 
^[a-z]+$ 匹配由26个英文字母的小写组成的字符串 
^[A-Za-z0-9]+$ 匹配由数字和26个英文字母组成的字符串 注意\w包含下划线_ 
^\w+$ 匹配由数字、26个英文字母或者下划线组成的字符串 
常用数字正则和常用字符串正则,是最基本的正则应用,读者可以作为入门的练习,试试能不能快速的读懂其中的含义。

匹配中文字符 普遍使用的正则是[\u4e00-\u9fa5],但这个范围并不完整。例如: 
/[\u4e00-\u9fa5]/.test( '⻏' ) // 测试部首⻏,返回false 
根据Unicode 5.0版编码,要准确的判断一个中文字符要包括: 
范围 含义 范围 含义 
2E80-2EFF CJK 部首补充 2F00-2FDF 康熙字典部首 
3000-303F CJK 符号和标点 31C0-31EF CJK 笔画 
3200-32FF 封闭式 CJK 文字和月份 3300-33FF CJK 兼容 
3400-4DBF CJK 统一表意符号扩展 A 4DC0-4DFF 易经六十四卦符号 
4E00-9FBF CJK 统一表意符号 F900-FAFF CJK 兼容象形文字 
FE30-FE4F CJK 兼容形式 FF00-FFEF 全角ASCII、全角标点 
因此,正确的匹配中文字符正则表达式为: 
var rcjk = /[\u2E80-\u2EFF\u2F00-\u2FDF\u3000-\u303F\u31C0-\u31EF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FBF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF]+/g; 
如果不希望匹配标点、符号,在正则中去掉对应的范围即可: 
3000-303F CJK 符号和标点 FF00-FFEF 全角ASCII、全角标点

匹配双字节字符(包括汉字在内) [^\x00-\xff],可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1),代码示例如下: 
console.info( "abc".replace( /[^\x00-\xff]/g,"aa" ).length ) // 3 
console.info( "汉字".replace( /[^\x00-\xff]/g,"aa" ).length ) // 4 
console.info( "abc汉字".replace( /[^\x00-\xff]/g,"aa").length ) // 7

匹配HTML标记的正则表达式 先说说网上流传的版本: 
<(\S*?)[^>]*>.*?</\1>|<.*? /> 
*? *表示0个或多个,?表示0个或1个,两个叠加起来标识0个多个,与*的功能重叠 
(\S*?) 标签的长度必须大于0,因此不能用*? 
|<.*?\/> 没有分组,无法获取以<div/>这种自关闭格式书写的标签 
</\1> 
<.*? /> 有的标签是不关闭的,比如<br><hr>,因此不能强制关闭 
修正如下: 
var rtag = /^<([a-z]+)\s*\/?>.*(?:<\/\1>)?$/i 
rtag.exec( '<-div></-div>') // null 
rtag.exec( '<div>abc') // ["<div>abc", "div"] 
这个表达式也不完善,比如第二条测试语句,这么写是为了能提取中包含了文本内容的标签,如果要严格匹配,可再次修改为: 
var rtag = /^<([a-z]+)\s*\/?> (?:<\/\1>)?$/i // 去掉了中间的.* 
这个正则的应用范围仅限于简单的标签匹配、提取,不能匹配嵌套标记。

匹配首尾空白字符的正则表达式 先说说网上流传的版本: 
^\s*|\s*$ 
可以删除行首行尾的空白字符,例如: 
' \t \n\r abc \t \n\r '.replace( /^\s*|\s*$/g, '' ) // abc 
但是用\s*不能判断出字符串是否在开头或结尾处有\s,例如: 
/^\s*|\s*$/.test( 'abc' ) // true 
修正如下: 
^\s+|\s+$ 
' \t \n\r abc \t \n\r '.replace( /^\s+|\s+$/g, '' ) // abc 
/^\s+|\s+$/.test( 'abc' ) // false

匹配Email地址的正则表达式 先介绍下Email的规则:local-part@domain 
 local-part最长64,domain最长253,总长最长256 
 local-part可以使用任意ASCII字符: 
 大小写英文字母 a-z,A-Z 
 数字 0-9 
 字符 !#$%&'*+-/=?^_`{|}~ 
 字符 .不能是第一个和最后一个,不能连续出现两次 
 但是有些邮件服务器会拒绝包含有特殊字符的邮件地址 
 domain(域名)仅限于26个英文字母、10个数字、连词号- 
 连词号-不能是第一个字符 
 顶级域名(com、cn等)长度为2到6个 
先说说网上流传的版本: 
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* 
() 莫名奇妙的分组,如果只分组不记录,可以使用(?:) 
@\w domain不能包含下划线_ 
\w+([-.]\w+)* 顶级域名不符合规则 
修正如下: 
var remail = /^([\w-_]+(?:\.[\w-_]+)*)@((?:[a-z0-9]+(?:-[a-zA-Z0-9]+)*)+\.[a-z]{2,6})$/i 
remail.exec( 'nuysoft@gmail.com' ) // "nuysoft@gmail.com", "nuysoft", "gmail.com"] 
remail.exec( 'nuysoft@gmail.comcomcom' ) // null 
remail.exec( 'nuysoft@_gmail.com ) // null 
修正后的正则有如下局限性: 
 不支持中文邮箱、中文域名,之所以不在其中支持是因为我个人的爱好倾向,反感这类华而不实的玩意 
 不支持特殊符号,避免非邮件服务器拒绝,如果需要,可以添加。 
参考文章: 
http://en.wikipedia.org/wiki/Email_address 
http://baike.baidu.com/view/119298.htm

匹配网址URL的正则表达式 先说说网上流传的版本: 
[a-zA-z]+://[^\s]* 
粗糙,没有对URL中各个块进行分组 
修正如下(又一段网上流传的版本): 
var _url = "^((https|http|ftp|rtsp|mms)?://)?" // 
+ "(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" // ftp的user@ 
+ "(([0-9]{1,3}.){3}[0-9]{1,3}" // IP形式的URL- 199.194.52.184 
+ "|" // 允许IP和DOMAIN(域名) 
+ "([0-9a-z_!~*'()-]+.)*" // 域名- www. 
+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]." // 二级域名 
+ "[a-z]{2,6})" // first level domain- .com or .museum 
+ "(:[0-9]{1,4})?" // 端口- :80 
+ "((/?)|" // a slash isn't required if there is no file name 
+ "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$"; 
var rurl = new RegExp( _url, 'i' ); 
测试: 
rurl.exec( 'baidu.com' ) // ["baidu.com", undefined, undefined, undefined, undefined, "baidu.com", undefined, "baid", undefined, undefined, "", "", undefined] 
rurl.exec( 'http://baidu.com' ) // 
rurl.exec( 'http://www.baidu.com' ) // ["http://baidu.com", "http://", "http", undefined, undefined, "baidu.com", undefined, "baid", undefined, undefined, "", "", undefined] 
rurl.test( 'baidu' ) // true 
看来不怎么也好用,有待学习TODO。

匹配帐号是否合法 先说说网上流传的版本: 
^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 
(字母开头,允许5-16字节,允许字母数字下划线) 
限制必须以字母开头现在看来不合适,比如QQ登录平台 
限制不能以下划线开头也没有必要,比如百度就允许,因此简单点 
修正如下: 
var ruser = /\w{4,16}/

匹配国内电话号码 网上流传的版本很好用: 
\d{3}-\d{8}|\d{4}-\d{7} 
评注:匹配形式如 0511-4405222 或 021-87888822

匹配腾讯QQ号 网上流传的版本很好用: 
[1-9][0-9]{4,} 
评注:腾讯QQ号从10000开始

匹配中国邮政编码 网上流传的版本很好用: 
[1-9]\d{5}(?!\d) 
评注:中国邮政编码为6位数字

匹配身份证 先说说网上流传的版本: 
\d{15}|\d{18} 
d{15} 
\d{18} 可以判断,但是有些粗糙 
从身份证可以解析出地址、生日、性别等,因此特别说明一下: 
 身份证规则 
中国的身份证为15位(一代)或18位(二代),区别在于二代证只是在一代证的第七位数字前加了19和在末尾加了一位验证码 
 将15位升级为18位,并解析18位号码构成(地址、生日、性别) 
代码如下: 
function parseID(ID) { 
if ( ID.length == 15 ) { 
// 升级为18位 
ID = ID.substr( 0, 6 ) + "19" + ID.substr( 6 ); 
// 前17位对应的系数 
var rank = [ 
"7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2" 
]; 
// 前17为加权除以17后的余数对应的最后一位身份证号码 
var last = [ 
"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" 
]; 
// 加权和 
for ( var i = 0, sum = 0, len = ID.length; i < len; i++) 
sum += ID[ i ] * rank[ i ]; 
// 加上最后一位 
ID += last[ sum % 11 ]; 
} 
if ( ID.length != 18 ) return null; 
var match = rid.exec( ID ); 
return match ? { 
ID : ID, 
area : match[ 1 ], 
y : match[ 2 ], 
m : match[ 3 ], 
d : match[ 4 ], 
sex : match[ 5 ] % 2 
} : null; 
} 
限制: 
 这里只是解析出了地址代码,如何将代码转换为实际地址请问度娘。 
 返回对象中的sex为1(男)或0(女),并未做转换,如果页面显示需要,可以这样转换:sex ? "男" : "女" 
测试: 
console.info( parseID( "142327840821047" ) ); 
console.info( parseID("142327198408210470" ) ); 
参考资料: 
http://baike.baidu.com/view/118340.htm#1

匹配IP地址 先说说网上流传的版本: 
\d+\.\d+\.\d+\.\d+ 
\d 数字没有限制 
修正如下: 
var rip = /^(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])$/; 
rip.test( "192.168.1.1" ) // true 
rip.test( "0.0.0.0" ) // true 
rip.test( "255.255.255.255" ) // true 
rip.test( "256.255.255.255" ) // false 
进一步增加分组: 
var rip2 = /^([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])$/; 
rip2.exec( "192.168.1.1" ) // ["192.168.1.1", "192", "168", "1", "1"] 
rip2.exec( "0.0.0.0" ) // ["0.0.0.0", "0", "0", "0", "0"] 
rip2.exec( "255.255.255.255" ) // ["255.255.255.255", "255", "255", "255", "255"] 
rip2.exec( "256.255.255.255" ) // null
Javascript 相关文章推荐
Javascript 面向对象编程(一) 封装
Aug 28 Javascript
JavaScript支持的最大递归调用次数分析
Jun 24 Javascript
JavaScript插件化开发教程 (三)
Jan 27 Javascript
jQuery实现页面顶部显示的进度条效果完整实例
Dec 09 Javascript
Bootstrap轮播加上css3动画,炫酷到底!
Dec 22 Javascript
jQuery制作圣诞主题页面 更像是爱情影集
Aug 10 Javascript
js仿iphone秒表功能 计算平均数
Jan 11 Javascript
基于VUE.JS的移动端框架Mint UI的使用
Oct 11 Javascript
vue中实现左右联动的效果
Jun 22 Javascript
详解Vue源码学习之callHook钩子函数
Jul 25 Javascript
微信小程序显示倒计时功能示例【测试可用】
Dec 03 Javascript
微信小程序返回箭头跳转到指定页面实例解析
Oct 08 Javascript
jQuery源码分析-01总体架构分析
Nov 14 #Javascript
js Form.elements[i]的使用实例
Nov 13 #Javascript
jquery中使用ajax获取远程页面信息
Nov 13 #Javascript
JQuery模板插件 jquery.tmpl 动态ajax扩展
Nov 10 #Javascript
jBox 2.3基于jquery的最新多功能对话框插件 常见使用问题解答
Nov 10 #Javascript
Javascript中的isNaN函数使用说明
Nov 10 #Javascript
推荐40个非常优秀的jQuery插件和教程【系列三】
Nov 09 #Javascript
You might like
MYSQL数据库初学者使用指南
2006/11/16 PHP
mysql 字段类型说明
2007/04/27 PHP
基于PHP服务端图片生成缩略图的方法详解
2013/06/20 PHP
分享下php5类中三种数据类型的区别
2015/01/26 PHP
php开发微信支付获取用户地址
2015/10/04 PHP
php获取手机端的号码以及ip地址实例代码
2018/09/12 PHP
tp5(thinkPHP5框架)captcha验证码配置及验证操作示例
2019/05/28 PHP
Laravel服务容器绑定的几种方法总结
2020/06/14 PHP
jQuery 判断元素上是否绑定了事件
2009/10/28 Javascript
JS面向对象编程 for Cookie
2010/09/19 Javascript
改进版通过Json对象实现深复制的方法
2012/10/24 Javascript
JS+CSS设置img在DIV中只显示Img垂直居中的部分
2013/10/24 Javascript
javascript的数组和常用函数详解
2014/05/09 Javascript
Jquery动态添加及删除页面节点元素示例代码
2014/06/16 Javascript
把文本中的URL地址转换为可点击链接的JavaScript、PHP自定义函数
2014/07/29 Javascript
用jquery模仿的a的title属性的例子
2014/10/22 Javascript
js判断登录与否并确定跳转页面的方法
2015/01/30 Javascript
js 动态添加元素(div、li、img等)及设置属性的方法
2016/07/19 Javascript
AngularJS 路由详解和简单实例
2016/07/28 Javascript
浅谈javascript中的 “ &amp;&amp; ” 和 “ || ”
2017/02/02 Javascript
VUE预渲染及遇到的坑
2018/09/03 Javascript
angularJs中orderBy筛选以及filter过滤数据的方法
2018/09/30 Javascript
javascrit中undefined和null的区别详解
2019/04/07 Javascript
微信小程序登录数据解密及状态维持实例详解
2019/05/06 Javascript
python将多个文本文件合并为一个文本的代码(便于搜索)
2011/03/13 Python
Python中time模块与datetime模块在使用中的不同之处
2015/11/24 Python
详解Python中的文件操作
2016/08/28 Python
Python 3.x基于Xml数据的Http请求方法
2018/12/28 Python
Flask框架学习笔记之使用Flask实现表单开发详解
2019/08/12 Python
通过python实现windows桌面截图代码实例
2020/01/17 Python
Python爬虫制作翻译程序的示例代码
2021/02/22 Python
HTML5新特性 多线程(Worker SharedWorker)
2017/04/24 HTML / CSS
2014国庆节餐厅促销活动策划方案
2014/09/16 职场文书
大一新生检讨书
2014/10/29 职场文书
优秀班主任事迹材料
2014/12/16 职场文书
2015财务年度工作总结范文
2015/05/04 职场文书