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 22 Javascript
jquery 选择器引擎sizzle浅析
Feb 06 Javascript
WebGL利用FBO完成立方体贴图效果完整实例(附demo源码下载)
Jan 26 Javascript
浅谈jquery之on()绑定事件和off()解除绑定事件
Oct 26 Javascript
jQuery双向列表选择器DIV模拟版
Nov 01 Javascript
JS中append字符串包含onclick无效传递参数失败的解决方案
Dec 26 Javascript
微信小程序之购物车功能
Sep 23 Javascript
前端必备插件之纯原生JS的瀑布流插件Macy.js
Nov 22 Javascript
在 webpack 中使用 ECharts的实例详解
Feb 05 Javascript
利用React Router4实现的服务端直出渲染(SSR)
Jan 07 Javascript
vue实现短信验证码输入框
Apr 17 Javascript
微信小程序报错: thirdScriptError的错误问题
Jun 19 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
《一拳超人》埼玉一拳下去,他们存在了800年毫无意义!
2020/03/02 日漫
自制短波长线天线频率预选器 - 成功消除B2K之流的镜像
2021/03/02 无线电
解析PHP自带的进位制之间的转换函数
2013/06/08 PHP
PHP5中GD库生成图形验证码(有汉字)
2013/07/28 PHP
Zend Framework教程之Loader以及PluginLoader用法详解
2016/03/09 PHP
ThinkPHP5分页paginate代码实例解析
2020/11/10 PHP
JS对URL字符串进行编码/解码分析
2008/10/25 Javascript
javascript之bind使用介绍
2011/10/09 Javascript
禁止IE用右键的JS代码
2013/12/30 Javascript
jQuery中[attribute*=value]选择器用法实例
2014/12/31 Javascript
javascript继承的六大模式小结
2015/04/13 Javascript
Javascript中setTimeOut和setInterval的定时器用法
2015/06/12 Javascript
js实现文字超出部分用省略号代替实例代码
2016/09/01 Javascript
getElementById().innerHTML与getElementById().value的区别
2016/10/27 Javascript
jquery设置css样式的多种方法(总结)
2017/02/21 Javascript
Angular动态添加、删除输入框并计算值实例代码
2017/03/29 Javascript
vue2.x 对象劫持的原理实现
2020/04/19 Javascript
在SAE上部署Python的Django框架的一些问题汇总
2015/05/30 Python
Python实现二维数组输出为图片
2018/04/03 Python
通过python顺序修改文件名字的方法
2018/07/11 Python
对Pytorch中nn.ModuleList 和 nn.Sequential详解
2019/08/18 Python
Python 多线程,threading模块,创建子线程的两种方式示例
2019/09/29 Python
解决pytorch DataLoader num_workers出现的问题
2020/01/14 Python
Python实现病毒仿真器的方法示例(附demo)
2020/02/19 Python
Python第三方包之DingDingBot钉钉机器人
2020/04/09 Python
Python filter过滤器原理及实例应用
2020/08/18 Python
HTML5之WebGL 3D概述(下)—借助类库开发及框架介绍
2013/01/31 HTML / CSS
字中字效果的实现【html5实例】
2016/05/03 HTML / CSS
Html5实现文件异步上传功能
2017/05/19 HTML / CSS
服装设计行业个人的自我评价
2013/12/20 职场文书
银行职员思想汇报
2013/12/31 职场文书
材料成型及控制工程专业求职信
2014/06/19 职场文书
公司合作意向书范文
2014/07/30 职场文书
高三复习计划
2015/01/19 职场文书
社区国庆节活动总结
2015/03/23 职场文书
Python竟然能剪辑视频
2021/05/25 Python