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 相关文章推荐
js 纯数字不重复排列的另类方法
Jul 17 Javascript
JQuery中关于jquery.js与jquery.min.js的比较探讨
May 15 Javascript
JS 实现导航栏悬停效果(续)
Sep 24 Javascript
使用jQuery快速解决input中placeholder值在ie中无法支持的问题
Jan 02 Javascript
PHPMyAdmin导入时提示文件大小超出PHP限制的解决方法
Mar 30 Javascript
jQuery实现查找链接文字替换属性的方法
Jun 27 Javascript
javascript 注释代码的几种方法总结
Jan 04 Javascript
Vue过滤器的用法和自定义过滤器使用
Feb 08 Javascript
JS 正则表达式验证密码、邮箱格式的实例代码
Oct 28 Javascript
详解Vue中组件的缓存
Apr 20 Javascript
javascript实现搜索筛选功能实例代码
Nov 12 Javascript
Vue使用Ref跨层级获取组件的步骤
Jan 25 Vue.js
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
php中通过正则表达式下载内容中的远程图片的函数代码
2012/01/10 PHP
php格式输出文件var_export函数实例
2014/11/15 PHP
PHP扩展迁移为PHP7扩展兼容性问题记录
2016/02/15 PHP
Laravel学习笔记之Artisan命令生成自定义模板的方法
2018/11/22 PHP
yii2 url重写并隐藏index.php方法
2018/12/10 PHP
prototype Element学习笔记(篇二)
2008/10/26 Javascript
javascript 面向对象全新理练之继承与多态
2009/12/03 Javascript
测试你的JS的掌握程度的代码
2009/12/09 Javascript
分享一道笔试题[有n个直线最多可以把一个平面分成多少个部分]
2012/10/12 Javascript
杨氏矩阵查找的JS代码
2013/03/21 Javascript
JS定时刷新页面及跳转页面的方法
2013/07/04 Javascript
jQuery使用drag效果实现自由拖拽div
2015/06/11 Javascript
通过javascript进行UTF-8编码的实现方法
2016/06/27 Javascript
JS中append字符串包含onclick无效传递参数失败的解决方案
2016/12/26 Javascript
详解vue项目构建与实战
2017/06/27 Javascript
ionic2懒加载配置详解
2017/09/01 Javascript
原生JS实现的简单小钟表功能示例
2018/08/30 Javascript
在vue中更换字体,本地存储字体非引用在线字体库的方法
2018/09/28 Javascript
Node.js中出现未捕获异常的处理方法
2020/06/29 Javascript
javascript实现点击按钮切换轮播图功能
2020/09/23 Javascript
python实现的阳历转阴历(农历)算法
2014/04/25 Python
Python守护进程(daemon)代码实例
2015/03/06 Python
Python实现高斯函数的三维显示方法
2018/12/29 Python
使用python计算三角形的斜边例子
2020/04/15 Python
在django中查询获取数据,get, filter,all(),values()操作
2020/08/09 Python
opencv+pyQt5实现图片阈值编辑器/寻色块阈值利器
2020/11/13 Python
使用tkinter实现三子棋游戏
2021/02/25 Python
利用CSS3的flexbox实现水平垂直居中与三列等高布局
2016/09/12 HTML / CSS
世界最大的私人旅行指南出版商:孤独星球
2016/08/23 全球购物
New Era英国官网:美国棒球帽品牌
2018/03/21 全球购物
奥地利智能家居和智能生活网上商店:tink.at
2019/10/07 全球购物
水利学院求职自荐书
2014/02/01 职场文书
python 模块重载的五种方法
2021/04/24 Python
SpringMVC 整合SSM框架详解
2021/08/30 Java/Android
IIS服务器中设置HTTP重定向访问HTTPS
2022/04/29 Servers
MYSQL如何查看操作日志详解
2022/05/30 MySQL