Thursday, April 08, 2010

0408:(ZT)Javascript与正则表达式个人总结与收录

Javascript与正则表达式个人总结与收录--基础篇

一、正则表达式的定义

正则表达式是一种可以用于模式匹配和替换的强有力的工具。

二、正则表达式的作用

  1、测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个模式,这也称为数据有效性验证。     
2、替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后将其删除,或者替换为别的内容。     
3、根据模式匹配从字符串中提取一个子字符串。随后可以用来在文本或输入字段中查找特定文字。

三、正则表达式的常见写法

现在很多正则表达式都采用了perl风格的写法,即把正则表达式的内容放在/ /中间,看起美观,最主要的是实用,方便辨别。

当然,如果不闲麻烦也可以写成如下的格式:

    var re = new RegExp (“regContent”);

四、正则表达式的“元字符”

所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。

较为常用的元字符如下:

“+”元字符规定其前导字符必须在目标对象中连续出现一次或多次。

示例:/Ro+/ 因为上述正则表达式中包含“+”元字符,所以可以与类似“Ro”,“Rocky”,“Roof”等在字母R后面连续出现一个或多个字母o的字符串相匹配。

“*”元字符规定其前导字符必须在目标对象中出现零次或多次。

示例:/Ro*/ 因为上述正则表达式中包含“*”元字符,所以可以与类似 “Ricky”, “Rocky”或者 “Roof”等在字母R后面连续出现零个或多个字母o的字符串

               匹配。   

“?”元字符规定其前导对象必须在目标对象中连续出现零次或一次。 

示例:/Ro?/ 因为上述正则表达式中包含“?”元字符,所以可以与目标对象中的 “Ricky”,“Rocky”这样在字母R后面连续出现零个或一个字母o的字符串匹配。

五、正则表达式的限定符

      有时候不知道要匹配多少字符。为了能适应这种不确定性,需要用到正则表达式中的限定符。

{n}:     n 是一个非负整数,表示匹配确定的 n 次。例如,o{2} 不能匹配 “Rocky” 中的 o,但是能匹配 “Roof” 中的两个 o。  

{n,}:    n 是一个非负整数,表示至少匹配 n 次。例如,o{2,} 不能匹配 “Rocky” 中的 o,但能匹配 “Roof”或“Whoooooa” 中的o。

{n,m}:   m 和 n 均为非负整数,其中n <= m,表示最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 “Whoooooa” 中的前三个 o

六、正则表达式中的定位符

正则表达式中的定位符用于规定匹配模式在目标对象中的出现位置。

“^”—— 定位符规定匹配模式必须出现在目标字符串的开头  

“$”—— 定位符规定匹配模式必须出现在目标对象的结尾  

“\b”—— 定位符规定匹配模式必须出现在目标字符串的开头或结尾的两个边界之一  

“\B”——定位符则规定匹配对象必须位于目标字符串的开头和结尾两个边界之内, 即匹配对象既不能作为目标字符串的开头,也不能作为目标字符串的结尾。

示例:

/^Ro/ 可以与类似 “Rocky”,“Rock”或“Roof”的字符串相匹配。

/ball$/ 可以与类似“football”,“basketball”或 “baseball”的字符串相匹配。

/\bon/ 可以与类似 “one”,“once”的字符串相匹配。

/on\b/   可以与类似“sensation”,“generation”的字符串相匹配

/on\B/ 可以与类似“song”,“tone”,“tongue”的字符串相匹配()

              注:/\Bon此处匹配作用相同/

七、正则表达式中的其他常见符号

“()”:    在正则表达式中使用括号把字符串组合在一起。“()”符号包含的内容必须同时出现在目标对象中才可匹配,当然有时在功能没有影响的情况下,会为了方便代码检查等加上括号运算符。

“|”:     在正则表达式中实现类似编程逻辑中的“或”运算。例如:/Rocky|Ricky/ 上述正则表达式将会与目标对象中的 “Rocky”或“Ricky”。

“[]”:    指定可以取的字符范围,如 [0-9] 可以匹配从0到9范围内的任何一个数字。

“[^]”: 规定目标对象中不能存在模式中所规定的字符串,即否定符。例如:/[^A-C]/ 上述字符串将会与目标对象中除A,B,和C之外的任何字符相匹配。

    例如:

        alert(/[^A-C]/.test('A'));   //false

        alert(/[^A-C]/.test('AB'));  //false

        alert(/[^A-C]/.test('AD'));  //true

        alert(/[^A-C]/.test('DF'));  //true

“\”:   转义符。当用户需要在正则表达式的模式中加入元字符,并查找其匹配对象时,可以使用转义符。例如:/R\*/会与“R*”匹配而非“Ro”或“Ri”等相匹配。

八、常用正则表达式匹配

\s:   用于匹配单个空格符,包括tab键和换行符;

\S:   用于匹配除单个空格符之外的所有字符;

\d:   用于匹配从0到9的数字;

\w:   用于匹配字母,数字或下划线字符;

\W:   用于匹配所有与\w不匹配的字符;

: 用于匹配除换行符之外的所有字符。

九、正则表达式常见的运算符等价转化关系

o{1,}     <=>   o+

o{0,}     <=>  o*

o{0,1}   <=>   o?

    \d      <=>   [0-9]

    \w     <=>    [a-zA-Z0-9_]

十、正则表达式运算符优先级

1.\                      转义符  

2.(),(?:),(?=),[]          圆括号和方括号  

3.*,+,?,{n},{n,},{n,m}   限定符  

4.^,$,\anymetacharacter   位置和顺序  

5.|                     “或”操作 

 

一、正则表达式中的量词

贪婪量词:

      先看整个字符串是不是一个匹配。如果没有发现匹配,它去掉最后字符串中的最后一个字符,并再次尝试。如果还是没有发现匹配,那么再次去掉最后一个字符串,这个过程会一直重复直到发现一个匹配或者字符串不剩任何字符。简单量词都是贪婪量词。

惰性量词:

      先看字符串中的第一个字母是不是一个匹配,如果单独着一个字符还不够,就读入下一个字符,组成两个字符的字符串。如果还没有发现匹配,惰性量词继续从字符串中添加字符直到发现一个匹配或者整个字符串都检查过也没有匹配。惰性量词和贪婪量词的工作方式恰好相反。

支配量词:

      只尝试匹配整个字符串。如果整个字符串不能产生匹配,不做进一步尝试。

image

 

?:当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。

二、 正则表达式高级使用

(?:pattern) :匹配 pattern 但不获取匹配结果,也就是说这是一个非捕获型匹配,不进行存储供以后使用。这在使用 "|" 字符来组合一个模式的各个部分是很有

                   用。例如要匹配 Rocky 和Ricky,那么R(?:o|i)cky较之 Rocky |Ricky表达更为简略。

(?=pattern) :正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串,匹配pattern前面的位置。这是一个非捕获型匹配,也就是说,该匹配不需要获取                      供以后使用。

示例:

alert(/Windows (?=95|98|NT|2000)/.test('Windows 2000'));   //true

alert(/Windows(?=95|98|NT|2000)/.test('Windows 2000'));   //false

                      alert(/Windows (?=95|98|NT|2000)/.test('Windows 3.1'));    //false

                   预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。   

(?!pattern) :负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串, 匹配后面不是pattern的位置,这也是一个非捕获型匹配。

示例:

                           alert(/Windows (?!95|98|NT|2000)/.test('Windows 2000'));   // false

                           alert(/Windows(?!95|98|NT|2000)/.test('Windows 2000'));   // true

                           alert(/Windows (?!95|98|NT|2000)/.test('Windows 3.1'));    // true

\数字:          反向引用,通过数字编号引用前面的内容

示例:

                           alert(/ba(na)\1/.test('banana'));  //true

                           alert(/(\d{4})\1(\d{2})\1/.test('12341234121234'));   //true

                           alert(/(\d{4})\1(\d{2})\2/.test('123412341212'));      //true

三、正则表达式中参数的使用

1、g:表明可以进行全局匹配。

①   对于表达式对象的exec方法,不加入g,则只返回第一个匹配,无论执行多少次均是如此,如果加入g,则第一次执行也返回第一个匹配,再执行返回第二个匹配,依次类推。

      例如:
             var regx=/user\d/;
             var str=“user18dsdfuser2dsfsd”;
             var rs=regx.exec(str);//此时rs的值为{user1}
             var rs2=regx.exec(str);//此时rs的值依然为{user1}
             如果regx=/user\d/g;则rs的值为{user1},rs2的值为{user2}

      通过这个例子说明:对于exec方法,表达式加入了g,并不是说执行exec方法就可以返回所有的匹配,而是说加入了g之后,我可以通过某种方式得到所有的匹配,这里的方式对于exec而言,就是依次执行这个方法即可。
②   对于match方法,不加入g,只是返回第一个匹配,而且一直执行match方法也总是返回第一个匹配,但加入g,则一次返回所有的匹配(注意是“所有”)。

      例如:
             var regx=/user\d/;
             var str=“user1sdfsffuser2dfsdf”;
             var rs=str.match(regx);//此时rs的值为{user1}
             var rs2=str.match(regx);//此时rs的值依然为{user1}
             如果regx=/user\d/g,则rs的值为{user1,user2},rs2的值也为{user1,user2}
③  对于String对象的replace方法,表达式不加入g,则只替换第一个匹配,如果加入g,则替换所有匹配。
④  对于表达式对象的test方法,加g与不加g没有什么区别。
⑤  对于String对象的split方法,加g与不加g是一样的。

⑥  对于String对象的search方法,加不加g也是一样的。

2、i:忽略大小写匹配

示例:

        alert(/[A-Z]/.test('a'));  //false

        alert(/[A-Z]/i.test('a'));  //true

3、m:多行模式

示例:

           var toMatch = "First second\nthird fourth\nfifth sixth";

           var reg = /(\w+)$/g;

           alert(toMatch.match(reg));  // sixth

    假如将\n看作是换行符,此时也想匹配换行前的单词,即second,fourth,则可以使用多行模式:

           var toMatch = "First second\nthird fourth\nfifth sixth";

           var regm = /(\w+)$/gm;

           alert(toMatch.match(regm));   // second,fourth,sixth,

四、正则表达式中test,exec,match,search方法比较

test():  返回bool值,表示是否匹配成功。

exec(): 返回第一个匹配的字符串

match():返回所有匹配的字符串(数组)

search():返回在字符串中出现的第一个匹配的位置

示例:

       var sToMatch = “a bat, a Cat, a fAt baT, a faT cat”;

       var re = /at/;

       re.test(sToMatch);    //true

       re.exec(sToMatch);   //返回第一个at的实例(即bat中的那个)

       re.match(sToMatch);  //返回at,at,At,aT,aT,at组成的数组

       re.search(sToMatch);  //3

五、备注

1、  使用限定符时,如o{0,1},注意在逗号和两个数之间不能有空格

2、  一般来说,当“^”出现在 “[]”内时就被视做否定运算符;而当“^”位于“[]”之外,或没有“[]”时,则应当被视做定位符。  

 

光说不练假把式,下面通过对字符串的常见操作实现对相关理论的简单回顾。

声明字符串处理对象:

var stringUtil = new Object();



1、将字符串首字母大写



方法一、首字符匹配英文字母,则用其大写形式替换



1 function capitalize(str){
2 return str.replace(/^\w/, str.substr(0, 1).toUpperCase());
3 }



方法二、



1 stringUtil.capitalize = function(str) {
2 return str.replace(/^\w/, function(s) {
3 return s.toUpperCase();
4 });
5 }



2、计算字符串长度(汉字算两个字节)



1 stringUtil.lenReg = function(str) {
2 return str.replace(/[^\x00-\xff]/g, " ").length;
3 }



3、去除字符串中的空白



代码



1 stringUtil.lTrim = function(str) {
2 /// <summary>去掉字符串左边的空格</summary>
3   return str.replace(/(^\s*)/g, "");
4 }
5
6 stringUtil.rTrim = function(str) {
7 /// <summary>去掉字符串右边的空格</summary>
8   return str.replace(/(\s*$)/g, "");
9 }
10
11 stringUtil.trim = function(str) {
12 /// <summary>去除字符串开头结尾的空白</summary>
13   return str.replace(/(^\s*)|(\s*$)/g, "");
14 }
15 



4、去除字符串中的相同字符



1 stringUtil.trimSameChar = function(str) {
2 var re = /(.)(.*)\1/g;
3 while (str.match(re) != null) {
4 str = str.replace(re, "$1$2");
5 }
6 return str;
7 }



5、去除字符串中的HTML标签



1 stringUtil.trimHTML = function() {
2 //(?:.|\s)表示匹配<后面的任何文本,然后跟着一个>,*?为惰性量词,表示零次或多次出现
3   var reTag = /<(?:.|\s)*?>/g;
4 return this.replace(reTag, "");
5 };



对比:通过普通方式和正则表达式取得URL中的参数值



普通循环遍历处理:



代码



1 function getUrlParamValue(fieldName) {
2 /// <summary>取得网址中的参数,相当于.net的Request.QueryString方法,
         如果没有取到值,返回null</summary>
3   /// <param name="fieldName">查询的参数名</param>
4   var urlString = location.search;//假如是:default.aspx?id=1&page=1
5 if (urlString.length > 0) {
6 var paramsArr = urlString.split('?')[1].split('&');//{id=1} {page=1}
7 for (var i = 0; i < paramsArr.length; i++) {
8 var paramValue = paramsArr[i].split('=');
9 //如果与所需参数相同,则返回其参数值
10 if (paramValue[0].toUpperCase() == fieldName.toUpperCase()) {
11 return paramValue[1];
12 break;
13 }
14 }
15 return;
16 }
17 else {
18 return null;
19 }
20 }



正则表达式处理:



分析:URL的参数可能有多个,所以需要的参数值有可能出现在?后面,也有可能出现在&后面,故此时需要同



时匹配二者,而此参数的后面还可能有零个或多个参数,所以要通过[^\&]*进行匹配,最后为了忽略大小写可以在



构造正则表达式的时加入i 参数。



代码



1 function getUrlParamValueByReg(fieldName) {
2 var sValue = location.search.match(new RegExp("[\?|\&]" + fieldName
+ "=([^&]*)", "i"));
3 return sValue ? sValue.toString().split(",")[1] : null;
4 }
5



通过比较,不难看出正则表达式的强大啊。。。





总结了一些常见的表单验证类的操作,供以后备用。。。



var validateUtil = new Object();

validateUtil.isEmpty = function(id) {
/// <summary>检测元素</summary>
/// <param name="id">元素id</param>
var str = stringUtil.trim($(id).value);
if (str.length == 0) {
return true;
}
return false;
}

validateUtil.isContainChinese = function(str) {
/// <summary>检测字符串中是否有汉字</summary>
var reg = /[\u4e00-\u9fa5]/;
return reg.test(str);
}

validateUtil.isValidUserName = function(strUserName) {
/// <summary>检测用户名,长度在6到15位之间,且只能由中英文、数字、-、_构成,
///中文算两个字符</summary>
if (stringUtil.len(strUserName) >= 6 && stringUtil.len(strUserName) <= 15) {
var reg = /([\u4e00-\u9fa5]|[\w-])/g;
return reg.test(strUserName);
}
return false;
}

validateUtil.isValidPassword = function(strPass) {
/// <summary>检测密码,密码长度在6到15位之间,且只能由英文字母、数字、-、_构成,
///且首位必须是英文字母</summary>
var reg = /^[a-zA-Z][\w-]{5,15}$/;
return reg.test(strPass);
}

validateUtil.isValidEmail = function(strEmail) {
/// <summary>检测Email地址是否合法</summary>
var reg = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
return reg.test(strEmail);
}

validateUtil.isValidDate = function(strDate, separator) {
/// <summary>检测日期是否合法</summary>
/// <param name="separator">可选项:年月日之间的分隔符,只可以为'-'或'/',
默认为'-'</param>
if (strDate.length == 0) {
return false;
}
//根据正则表达式判断基本的日期格式是否正确:(1|2)xxx-xx-xx
if (separator == '/') {
var reg = /^(1|2)([\d]){3}\/[\d]{2}\/[\d]{2}/;
if (!reg.test(strDate)) {
return false;
}
}
else {
var reg = /^(1|2)([\d]){3}-[\d]{2}-[\d]{2}/;
if (!reg.test(strDate)) {
return false;
}
}
//去除日期中的 '-' 或 '/' 分隔符
var strFormatDate = strDate.replace(/(-|\/)/g, '');
var year, month, day;
//取得年月份的具体值
year = isIE ?
strFormatDate.substr(0, 4) : strFormatDate.substr(0, 4) + 1900;
month = strFormatDate.substr(4, 2);
day = strFormatDate.substr(6, 2);
//检测年月日的合法性
return checkDate(year, month, day);
}

validateUtil.isValidCid = function(strId) {
/// <summary>检测身份证号码是否合法,若为15位则验证成功后返回转换为18位的身份证号,
///若为18位则验证成功后则返回true</summary>
strId = strId.toUpperCase();
//判断基本的身份证号码格式是否正确:15位时全为数字,18位前17位为数字,
最后一位是校验位,可能为数字或字符X。
if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(strId))) {
return false;
}
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10
//下面分别分析出生日期和校验位
var strIdLength = strId.length;
var reg;
var year, month, day;
if (strIdLength == 15) {
reg = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/);
//如"123456789123456",则arrSplit为123456789123456,123456,78,91,23,456
var arrSplit = strId.match(reg);

//检查生日日期是否正确
var year = '19' + arrSplit[2];
var month = arrSplit[3];
var day = arrSplit[4];
if (!checkDate(year, month, day)) {
//输入的身份证号里出生日期不对
return false;
}
else {
//将15位身份证转成18位
return strId.substr(0, 6) + '19' + strId.substr(6, 9) + 'X';
}
}
if (strIdLength == 18) {
reg = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
//如"12345678912345678X",则arrSplit为12345678912345678X,123456,7891,23,
45,678,X
var arrSplit = strId.match(reg);

//检查生日日期是否正确
var year = '19' + arrSplit[2];
var month = arrSplit[3];
var day = arrSplit[4];
if (!checkDate(year, month, day)) {
//输入的身份证号里出生日期不对
return false;
}
else {
//检验18位身份证的校验码是否正确。
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
var validStrId;
var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5,
8, 4, 2);
var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4',
'3', '2');
var nTemp = 0, i;
for (i = 0; i < 17; i++) {
nTemp += strId[i] * arrInt[i];
}
validStrId = arrCh[nTemp % 11];
if (validStrId != strId.substr(17, 1)) {
//18位身份证的校验码不正确,最后以为应该是+ validStrId);
return false;
}
}
}
return true;
}

function checkDate(year, month, day) {
//月份不可大于12,天数不可大于31
if (parseInt(month, 10) <= 0 || parseInt(month, 10) > 12 ||
parseInt(day, 10) <= 0 || parseInt(day, 10) > 31) {
return false;
}
//判断是否是闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
//闰年2月不可大于29天
if (parseInt(month, 10) == 2) {
if (parseInt(day, 10) > 29) {
return false;
}
}
}
else {
//平年2月不可大于28天
if (parseInt(month, 10) == 2) {
if (parseInt(day, 10) > 28) {
return false;
}
}
}
var monthArr = new Array(1, 3, 5, 7, 8, 10, 12);
for (var i = 0; i < monthArr.length; i++) {
//“大月”天数不可大于31
if (monthArr[i] == parseInt(month, 10)) {
if (parseInt(day, 10) > 31) {
return false;
}
}
else {
//“小月”天数不可大于30
if (parseInt(day, 10) > 30) {
return false;
}
}
}
return true;
}

0 Comments:

Post a Comment

<< Home