正则整理
一:定义
正则是模式 ,模型,是用来匹配验证字符串的
1,定义模式 RegExp
2,匹配 .test方法 RegExp.prototype.text
3,捕获 . exec方法 返回的是数组,会把所有匹配项保存到数组里,如果正则和字符串不能匹配,则返回null。
1字面量 var reg=/\d/;
2new var reg=new RegExp("\\d");
eg: var str="孙" ; reg=new RegExp("^"+str+"[\\u4300-\\u9fa5]+$"); //构造函数灵活
var reg =/^\d$/;
//^表示必须以后边的字符开始,修饰的是后边的符号。\d表示0-9之间的一个数字
//$以他前边的衣服结尾,修饰的是前边的符号。
//+量词,修饰前边的字符出现一道多次的,相当于{1,}
//元字符:在正则中表示一些特定含义的字符叫元字符。正则中不仅可以有元字符,正常的字符同样可以出现。
reg = /1234/; "a1234b","398551234095"
reg=/^1234$/;
reg = /^[a-z]{1,}$/; //验证是不是全是字母 。 []表示多选一的“或”,或者表示连续出现的字符中的某一个
reg=/^[a-z]+$/i ; //出现在正则后边的字符叫模式修正符,在js中,只有三个修正符g、i、m。i表示忽略大小写,g表示全文查找,m表示多行查找。
var reg=/(ab|cd|xyz)/ ; //表示验证一个字符中,只要出现了ab或cd或xyz则成功;"149abs3"
var reg1=/^\d+(ab|cd|xyz)\d+$/; //ab或cd或xyz的前后必须是数字
var reg2=/^\d+ab|cd|xyz\d+$/; //区别下面的有括号的正则
var str1="48940xyz930" //reg1.exec(str1) ==>返回["48940xyz930","xyz"]
var str2="390ab";
var str3="4902abcd"; // reg2.exec(str3) ==>返回["4902ab"]
var str4="cd930ab";
var str5="xyz999ab";
var str6="84949@qq.com"//需要证邮箱
//邮箱:首先要给出你的网站规定的邮箱规则
//包括数字,字母,下划线和., 后边是@,再后边域名,再后是.点,最后的部分只能是字母
regMail=/^[\w.]+@\w+\.[a-z]+(\.[a-z]+)?$/i
//[+*]/ ;
//【【在[]里的单字符的元字符,不用转意,就表示这个字母表示的本身的意思】】
//量词元字符:+一到多次,*零到多次,?零到一次,{m,n},{m},{m,}
var regMail=new RegExp("^[\w.]+@\w+\.[a-z]+(\.[a-z]+)?$","i");
//在[]里的单字符的元字符不用转意,就表示字母的本身的意思
//量词元字符:?零到一次、 *零到多次、 +一到多次、{m,n}、 {m}、{m,}
var reg3=/^1234$/
var str7="asd1234"
二:非贪婪匹配
var innerHTML=document.body.innerHTML;
. [\s\S] [.\n];单字符的元字符,一但放到[]里,就失去了元字符的功能了
//就说是[.]和\.一样了
//+?*()|{}
//表示所有的字符的方式有[\s\S],[\D\d],[\w\W],(.|\n)这个方式有可能存在bug。
//但是[\B\b]这个不可以表示任意字符
var reg=/<div +id="content">[\s\S]+<\/div>/;//不带?,则按着贪婪匹配的方式,捕获到最后一个</div>
console.log(reg.exec(innerHTML)[0]);
var reg=/<div +id="content">[\s\S]+?<\/div>/;//在+后带?,则按非贪婪匹配的方式捕获到最近的一个</div>就结束
console.log(reg.exec(innerHTML)[0]);
三:问号的几种意义
//量词
var reg=/^a?$/ //要么是个空字符串,要么只是一个a,出现在实意字符的后边他表示这个实意字符出现0到1次,即是个量词
//非贪婪模式
var reg=/^a+?$/ //这次的?就不是量词了 表示非贪婪模式
var reg1=/\d+/
var reg2=/\d+?/
reg1.exec("ad123445533jk"); // 输出 ["123445533"]
reg2.exec("ad123445533jk") // 输出 ["1"]
var reg1=/^\d+(ab|cd|xyz)\d+$/;//ab或cd或xyz的前后必须是数字
var str1="48940xyz930";
reg1.exec(str1);//输出结果是["48940xyz930","xyz"];
//分组中的(子正则匹配不捕获)
//把?:放在括号的开始位置,表示不再把括号的内容当成一个子正则(匹配不捕获)取消分组
var reg2=/^\d+(?:ab|cd|xyz)\d+$/;//ab或cd或xyz的前后必须是数字
var str1="48940xyz930";
reg1.exec(str1);//输出结果是["48940xyz930"]
//前提条件(断言assert)
//正向预查和负向预查(带条件的正则表达式)
//条件是匹配以字符结尾的连续数字的正则
var str2="did4905dkd77d&#"
var str3="did4905dkd89dac"
var reg3=/\d{2,}(?=[a-z]+$)/;//括号里的根本就不参与捕获,只是这个正则成立的条件(前提),【只修饰左边的】
var reg4=/\d{2,}(?:[a-z]+$)/;//这是取消分组,但是可以把89dac捕获到,但不会把dac单独再捕获到了
var reg5=/\d{2,}([a-z]+$)/;
var reg6=/\d{2,}[a-z]+$/
reg3.exec(str2);//null
reg3.exec(str3);//["89"];
reg4.exec(str3);//["89dac"];
reg5.exec(str3);//["89dac","dac"]
reg6.exec(str3);//["89dac"]
//负向预查
var reg7=/\d{2,}(?![a-z]+$)/;//(?后面不全是字母)
var str2="diddkd77d&#";//虽然也是在77后边有字母d,但d不是结尾,满足了正则的定义
var str3="diddkd89dac";//这个是以连续的多个字母结尾的,不满足reg5中规定的条件,所以匹配不成功
var str4="diddkd894dac";//对于这个字符串,奇葩的问题就出现了。把89看成满足条件的部分了,89后边是4,不是字母,按成立来对待了。
//需要注意的是:在写负向预查的正则时,尽量的严格,慎用。
//正向预查和负向预查是尽量的让条件部分满意
reg7.exec(str2); //["77"]
reg7.exec(str3); //null
reg7.exec(str4); //["89"]
var reg8=/\d{2,}([^a-z]+$)/ ;//(?后面不出现字母)
var str5="diddkaj4758*%$("
reg8.exec(str2); //null
reg8.exec(str3); //null
reg8.exec(str4); //null
reg8.exec(str5); //["4758*%$(","*%$("]
四:分组
//子正则:小括号
//如果验证重复的字符怎么办?
var str1 = "aaaaaaaa";
var str2 = "abcdefg";
//分组的概念 ()
var reg = /((\w)(\w)(\w))/;
reg.exec(str1); //["aaa", "aaa", "a", "a", "a"]
reg.exec(str2); //["abc", "abc", "a", "b", "c"]
//分组的引用 如果正则没有加g 则exec和match功能一样
var reg = /^(\d)\d\1$/;
var str3 = "121";
str4 = "212";
var reg = /^(\w)\1+$/;
var str = "aaa";
//alert(reg.exec("aaaaaa")); //["aaaaaa","a"]
reg.exec(str); //["aaa", "a"]
//用其它方式获得分组(子正则)捕获到的内容
var reg = /(\w)(\w)(\w)/;
var str = "abcdefghighlmn";
reg.test(str); //true
reg.exec(str); //["abc", "a", "b", "c"]
//正则实例运行之后,如果此正则上有分组,则会自动把分组捕获到的内容分别赋值给构造函数的$1,$2,$3.....$9
RegExp.$1; //"a"
RegExp.$2; //"b"
RegExp.$3; //"c"
/*RegExp.$4; //"" 空字符串
RegExp.$5; //""
RegExp.$9; //""
RegExp.$_; //"abcdefghighlmn"*/
五:元字符
// 实意元字符 \d\w\s
//非实意字符(表示某种逻辑) \b 分割常用的\w和不常用的\W的 str"abc@你好zxv%f**998"
//表示位置的元字符
var reg=/^\s*$/; //一般来做空验证或非空验证
//表示数量的元字符
// + {1,n} * {0,n} ? {0,1} 【【 不知道多少空格可以用+】】
//转意字符 \ [.] 和\. 一样了
//表示元字符本身的时候,需要用\转意一下。
//var reg=/[^a-z]/;//取非集;除a-z之外的任意字符
// 逻辑运算的或运算
//[abcdef]// 其中任意一个
//左|右//
//表示所有的字符方式有 [\s\S] [\d\D] [\w\W] 但是[\b\B] 不可以
\d \D这是\d的非集
\w [A-Za-z0-9_] 常用字符集(大小写字母、数字、下划线) \W [^A-Za-z0-9_]
\s 一切不可见的字符集(空白字符)
\S
[0-9]
[xyz] 匹配所包含的任意一个字符
[0-100] 0 1
. 除换行回车外的任意一个字符
\n string换行符
如果想匹配任意字符怎么办呢?
reg=/^(.|\s)+$/;
reg=/^[\S\s]+$/;"abcddi9d","aaaaaaaa"
// var reg=/^[\d\D]+$/;
// var str="a1,3.4/52-=&*24jsk"
// reg.exec(str); // ["a1,3.4/52-=&*24jsk"]
//
//
// var reg=/[abc]/;
// reg.exec(str); //["a"]
var reg1=/MSIE (6|7|8|9|10)/;
var str=window.navigator.userAgent;
console.log(str);
reg1.test(str);
reg1.exec(str);
console.log(reg1.exec(str));
console.dir(reg1.exec(str));
console.log((reg1.exec(str)) instanceof Array);
console.log(Object.prototype.toString.call(reg1.exec(str)));
六:模式修正符
//i,m,g 是对正则功能的补充
var reg = /^\d/img;
// reg.ignoreCase;//如果不设置修正符i,则这个属性的值是false
// reg.multiline; //同理上面的i ,只用在加了^ 或$,并且字符串中有换行字 符的前提下才有意义,并且一般情况下和g连用
// reg.global;
reg = /^\d+/mg;//多行全局查找,m只有当字符串中加了换行的时候才有意义
reg2 = /\w$/
var str = "2dkdf\n3dkdi\n4dkdk\n5kdkd";
var a = str.match(reg);
// alert(a); //["2", "3", "4", "5"]
console.log(a);
var str = "192.168.1.100";
str.split(".");
var reg = /\d+/g;
//alert(str.match(reg)); //["192", "168", "1", "100"]
//alert(reg.exec(str)); //按点击弹出:["192"] ["168"] ["1"] ["100"] null ["192"] ......在执行的时候吗,会去根据两个属性值去实现捕获 reg.lastIndex的值默认是0; 它是本次正则匹配的起始索引位置。
//reg.global 如果是false 则正则只做一次查找,reg.lastIndex的值永远是0;
//reg.global如果是true 会自动修改reg.lastIndex的值 将其修改为本次匹配结果的后边字符的索引位置,
//如果当次匹配没有成功(test返回了false,exec返回了null) 则会重置reg.lastIndex的值为0;
//简单的正则捕获中 尽量用match方法
str.match(reg);
RegExp.prototype.allExec= function (str) {
if(this.global){
this.lastIndex=0
var a=[]; //存放每一次捕获到结果
var result=null;
while( result=this.exec(str)){
a.push(result);
};
return a;
}else{
return this.exec(str);
}
}
var reg1 = /\d/g;
var str1 = "abcdef8";
reg1.test(str1);//true;
var str2 = "4abcdefg";
reg1.test(str2);//false //true //false //true
七:replace方法
var str="abc";//把此字符串反转成cba
str.replace(/(\w)(\w)(\w)/,"$3$2$1");
var str0="123456973";
//凡是值类型的上的方法,都不会修正原实例
var newStr=str0.replace(/\d/g,"a");
//下面的数组只是为了让索引1和a对应,索引2和b对应......
var a=["","a","b","c","d","e","f","g","h","i"];
var newStr=str0.replace(/\d/g,function(){
//此正则每匹配到一次字符,则运行一次此方法,并且传三个参数给这个方法,分别的0当次正则捕获到的结果,1是此结果在输入字符串中的索引位置,2是输入字符串
//return a[arguments[0]];
//要求是:把1转成A,2转成大写B,3--C
return String.fromCharCode(64+arguments[0]/1);
//String.fromCharCode是把ASCII码转成字符
//65是A,64+1是A,
});
八:反转字符的两种方法
var str="abcdefg"
// 0123456
//str.split("").reverse().join("");//这是简单粗暴的方法
var newStr=str.replace(/\w/g,function(){
//str.length-1-arguments[1]//计算和当前字符对称的字符的索引位置
//找到对称位置上的字符并返回,这样则把原位置和对称位置上的字符交换了,实现了字符串的反转
//比如第一次运行时找到a的索引0,通过这个0找到和a对称的字符g(第0个和最后一个对称),然后让g替换a
return str.charAt(str.length-1-arguments[1]);
});
alert(newStr);
//第二种写法
var newStr=str.replace(/\w/g,function(a,b,c){
return c.charAt(c.length-1-b);
});
九:字符串去重
var str = "88888889999993333337777777222222";
var reg = /(\w)\1+/g;
//str.match(reg);
var newStr=str.replace(reg,function(a,b,c,d){
//1.总正则捕获到的结果 2.总结果在字符串中的索引位置 3.原字符串
//如果正则中有分组,则会在1和2之间,把每个分组捕获到的结果,当参数传进来
console.log(a,b,c,d);
return b;
});
console.log(newStr);
十:千分符的几种写法
//加上千分符后的结果如下:
//"7,654,321"
//思路:先不考虑从后往前加逗号,先考虑从向往后加逗号
"765,432,1"
str1=str.replace(/(\d{3})(?!$)/g,"$1,");
///(\d{3})(?!$)/g的(?!$)表示连续出现的三位数字的后边不能是字符串的结尾,这里使用的是负向预查
//alert(str1);
//第二种方法:正向预查
var str="7654321";
str2=str.replace(/(\d{3})(?=\d)/g,"$1,");
//正向预查只是条件,不能与匹配和捕获。
//正则在处理str时,第一次把987和6都计算了,但是987是正则匹配并且捕获的内容,虽然6也要满足,但不参与捕获。下一次再处理些字符串的时候,是从7的后边开始处理,而不是从6的后边处理。就是说(?=\d)只是前边的正则成立的前提条件(这叫assert,一些教材中译作断言)
//alert(str2);
var str3=str.split("").reverse().join("").replace(/(\d{3})(?=\d)/g,"$1,").split("").reverse().join("");
//alert(str3);
//第三种方法
var str="87654321";
//把这个字符串处理两次
//第一步:把正则拆分两部分87 654321
var str4=str.replace(/^(\d{1,3})((\d{3})+)$/,function(a,b,c,d,e,f){
return b+","+c.replace(/\d{3}(?!$)/g,function(){
console.log(a,b,c,d,e,f)
return arguments[0]+",";
});
})
//alert(str4);
//第四种方法
var str="87654321";
//加千分符其实是从后往前数,每三位加一个逗号
//问题是如何倒着数索引:正数是0,倒数就是str.length-1-0;正数是1,则倒数是str.length-1-1
//倒数的顺序号是:str.length-1-index;
var str5=str.replace(/\d(?!$)/g,function(a,b,c){
//先要搞清a,b,c是谁
var i=c.length-1-b;
if(i%3===0){
return a+",";
}else{
return a;
}
})
//alert(str5);
//第五种方法
var str="87654321";
var reg=/(\d)(?=(\d{3})+$)/g
var a=str.replace(reg,"$1,")
console.log(a);
//第六种方法
var reg=/\B(?=(?:\d{3})+\b)/g
str.replace(reg,",")
十一:汇总
1、元字符
[拥有特殊含义的元字符]
\d -> 匹配一个0-9的数字,相当于[0-9],和它相反的是\D ->匹配一个除了0-9的任意字符
\w -> 匹配一个0-9、a-z、A-Z、_的数字或字符,相当于[0-9a-zA-Z_]
\s -> 匹配一个空白字符(空格、制表符...)
\b -> 匹配一个单词的边界
\t -> 匹配一个制表符
\n -> 匹配一个换行
. -> 匹配一个除了\n以外的任意字符
^ -> 以某一个元字符开头
$ -> 以某一个元字符结尾
\ -> 转移字符
x|y -> x或者y的一个
[xyz] -> x、y、z中的任意一个
[^xyz] -> 除了xyz中的任意一个字符
[a-z] -> 匹配a-z中的任意一个字符
[^a-z] -> 匹配除了a-z中的任意一个字符
() -> 正则中的分组
注意:
1)关于[]
a、[+] ->中括号中出现的所有字符都代表的是本身的意思
b、[12-65] ->这个不是12-65而是1/2-6/5三者中的一个
2)关于()
a、分组的作用是改变默认的优先级,例如:/^18|19$/,181、189、119、819、1819...都符合,而不是我们认为的18或19,但是改成/^(18|19)$/就是单纯的18或19了
b、可以在捕获大正则匹配的内容同时,把分组匹配的内容也进行捕获->分组捕获
c、分组引用,例如:/^(\d)(\w)\2\1$/,这里的\2是和第二个分组出现一模样的内容,\1是和第一个分组出现一模一样的内容,例如:"0aa0"就符合了
[代表数量的量词元字符]
* -> 0到多个
+ -> 1到多个
? -> 0到1个
{n} -> 出现n次
{n,} -> 出现n到多次
{n,m} -> 出现n到m次
注意:
1)关于?的几种情况
a、放在非量词元字符后面,代表出现0-1次
b、放在量词元字符后面,代表取消捕获时候的贪婪性,例如:reg=/\d+/; reg.exec("2015") -> "2015" 但是如果正则这样写 reg=/\d+?/; reg.exec("2015") -> "2"
c、在分组开头加?:,代表当前的分组只是匹配不进行捕获,例如:/^(?:\d+)$/
d、在分组开头加?=,正向预查,例如:/^zhufeng(?=1|2)$/ 只有"zhufeng1"和"zhufeng2"才符合
e、在分组开头加?!,负向预查,例如:/^zhufeng(?!1|2)$/ 除了"zhufeng1"和"zhufeng2"不符合,其他的只要是"zhufeng(任何的东西)"都符合
[代表本身意思的元字符]
除了以上的,在字面量方式中,我们出现的其他任意字符代表的都是自己本身的意思
var num=12;
var reg=/^\w"+num+"$/; ->这里"+num+"不是把变量的值拼接,而这里的不管是"还是+都是元字符
->对于需要拼接字符串和变量的方式我们只能使用实例方式创建正则
2、修饰符
i -> ignoreCase 忽略字母的大小写
g -> global 全局匹配 (加上g可以解决正则捕获时候的懒惰性)
m -> multiline 多行匹配
3、项目中常用的正则
1)有效数字的
var reg=/^[+-]?(\d|([1-9]\d+))(\.\d+)?$/;
var reg=/^[+-]?(\d|[1-9]\d+)(\.\d+)?$/
2)邮箱的
var reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
3)电话的
var reg = /^1\d{10}$/;
4)年龄在18-65之间的
var reg = /^((18|19)|([2-5]\d)|(6[0-5]))$/;
5)中文姓名
var reg = /^[\u4e00-\u9fa5]{2,4}$/;
6)身份证
var reg = /^(\d{6})(\d{4})(\d{2})(\d{2})(?:\d{2})(\d)(?:\d|X)$/;
//-> 130828(省市县) 1990(年) 12(月) 04(日) 06 1(奇数是男偶数是女) 7(数字或者X)
4、正则的匹配
reg.test([string]) ->true就是匹配成功 false->匹配不成功
5、正则的捕获
1)reg.exec([string])
-> 首先去匹配,匹配成功在捕获,返回的是一个数组; 如果匹配不成功返回的是null;
-> 正则的捕获即懒惰又贪婪
-> 解决懒惰性 在正则的末尾增加全局修饰符g
-> 解决贪婪性 在量词后面加?
其余更多的参照 "3.2-正则捕获.html"
6、正则实战应用之-replace
1)获取一个字符串中出现次数最多的字符和对应的次数,例如:var str = "zhufeng2015yangfanqihang";问哪几个字符出现的次数最多,一共有多少次?
2)千分符
var str="87654321"
->str.replace(/(\d)(?=(?:\d{3})+$)/g,'$1,') 只支持整数
->str.replace(/\B(?=(?:\d{3})+\b)/g,',') 支持小数
3)模板引擎绑定数据实现的原理
var ary = ["葛琪", "26", "china", "javascript"];
var str = "my name is {0},my age is {1},i com from {2},i can do {3}~~";
->"my name is 葛琪,my age is 26,i com from china,i can do javascript~~";
4)单词首字母大写
var str="my name is zhou xiao tian,my age is twenty five years old~~";
->把所有单词的首字母大写
5)格式化时间
var str="2015-5-3 12:9:13";
->"2015年05月03日 12时09分13秒"
6)queryURLParameter 获取地址栏中的参数
http://kbs.sports.qq.com/kbsweb/game.htm?mid=1467588&age=18
URL问号传参 -> mid=xxxx 就是我们传递过来的内容,我们需要获取mid,并且通过mid区分展示不同的内容
->{mid:"1467588",age:18}
7)在我们的utils.js这个DOM库中很多方法的编写中都使用了部分正则,大家自己回去看一下,尤其是getElementsByClass这个方法
…