正则详解1:正则必备基础知识

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<textarea id="result" rows="10" cols="100"></textarea>
	</body>
	<script src="../js/jquery.js" type="text/javascript" charset="utf-8"></script>
	<script type="text/javascript">
	/*----------------RegExp类型--------------------*/
	/*ECMAScript通过RegExp类型来支持正则。使用下面类似 Perl的语法,就可以创建一个正则表达式。*/
	//创建正则表达式
	var expression = /[bc]at/i;//expression = / pattern / flags(字面量方式)
	/*模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符类,限定符,分组,向前查找,以及反向引用。
	     标志(flags):每个正则表达式都可以带有一或多个标志(flags),用以标明正则表达式的行为。
	     标志的分类:
	     g:表示全局(global)模式,及模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止。
	     i:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写。
	     m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。
	*/
	/*元字符:与其他语言的正则表达式类似,模式中使用的所有元字符都必须转义,因为这些元字符在正则表达式中都有一或多种用途。
	     元字符包括:{ [ ( \ ^ $ | ? * + . ) ] }
	     例:匹配第一个"bat""cat",不区分大小写,var pattern1 = /[bc]at/i;
	     匹配第一个"[bc]at",不区分大小写,var pattern2 = /\[bc\]at/i;
	*/
	var pattern2 = new RegExp("[bc]at","i");//(RegExp构造函数)
	/*RegExp构造函数:它接收两个参数:一个是要匹配的字符串模式,另一个是可选的标志字符串。
	     双重转义:原因:由于构造函数的模式参数是字符串(例:字符\在字符串中通常被转义为\\,而在正则表达式字符串中就会变成\\\\)
	     双重转义的字符:元字符必须双重转义,那些已经转义过的字符,例(/\d/,"\\d")
	*/
	//字面量方式和RegExp构造函数方式的区别
	/*es3:正则表达式字面量始终会共享同一个RegExp实例,而构造函数创建的每一个新RegExp实例都是一个新实例。例:
	  es5:明确规定,使用正则表达式字面量必须像直接调用RegExp构造函数一样,每次都创建新的 RegExp实例(所以下面的两种方式等价)
	*/
	var re = null,i;
	for(i = 0;i < 10;i++){
		re = /cat/g;
		console.log(re.test("catastrophe"));
	};
	for(var i = 0;i < 10;i++){
		re = new RegExp("cat","g");
		console.log(re.test("catastrophe"));
	};
	// RegExp实例属性(没什么用)
	/*属性:
	  global:布尔值,是否设置了g标志
	  ignoreCase:布尔值,是否设置了i标志
	  lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从0算起
	  multiline:布尔值,是否设置了m标志
	  source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
	*/
	var pattern1 = /\[bc\]at/i;
	var result = pattern1.exec("[bc]at");
	console.log(result instanceof Array);//true
	var pattern2 = new RegExp("/\\[bc\\]at/i");
	// RegExp实例方法
	/*exec():是RegExp对象的主要方法,该方法专门是为捕获组而设计的。
	         参数:接收一个参数,即要应用模式的字符串
	         返回值:
	         1.包含第一个匹配项信息的数组(没有匹配项的情况下返回null),
	         在数组中第一项是与整个模式匹配的字符串,
	         其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,
	         则该数组只包含一项)。
	         2.包含两个额外的属性:index(匹配项在字符串中的位置) 
	         和 input(应用正则表达式的字符串)。
    */
    /*例子*/
  	var text = "mom and dad and baby";
  	var pattern = /mom( and dad( and baby)?)?/gi;
  	var matchs = pattern.exec(text);
  	console.log(matchs.index);//0
  	console.log(matchs.input);//"mom and dad and baby"
  	console.log(matchs[0]);// "mom and dad and baby"
  	console.log(matchs[1]);// " and dad and baby"
  	console.log(matchs[2]);// " and baby"
  	/*捕获组:这个例子的模式包含两个捕获组。最内部的捕获组匹配" and baby",而包含它的捕获组匹配" and dad"或者"and dad and baby".
  			当把字符串传入exec()方法中以后,数组中的第一项是匹配的整个字符串,第二项包含与第一个捕获组匹配的内容,第三项包含与第二个捕
  			获组匹配的内容
  	*/
  	//捕获组(补充知识点)
  	/*捕获组是什么:捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显示命名的组里,方便后面引用。可以在正则表达式内部,
  	                               也可以在正则表达式外部引用。
  	     捕获组的两种形式:普通捕获组和命名捕获组(通常所说的是普通捕获组)
  	                           语法:普通捕获组:(Expression);命名捕获组:(?<name>Expression)
  	                           
  	  *****扩展*****
  	     普通捕获组在大多数支持正则表达式的语言或工具中都是支持的,而命名捕获组目前只有.NET、PHP、Python等部分语言支持,据说Java会在7.0
  	     中提供对这一特性的支持。上面给出的命名捕获组的语法是.NET中的语法,另外在.NET中使用(?’name’Expression)与使用
  	  (?<name>Expression)是等价的。在PHP和Python中命名捕获组语法为:(?P<name>Expression)。
  	     另外需要说明的一点是,除(Expression)和(?<name>Expression)语法外,其它的(?...)语法都不是捕获组。
  	  *****扩展*****	
  	 
  	   捕获组编号规则:编号规则指的是以数字为捕获组进行编号的规则,编号为0的捕获组,指的是正则表达式整体,这一规则在支持捕获组的语言中,
  	                                 基本上都是适用的。
  	*/
  	/*1.普通捕获组编号规则:如果没有显示为捕获组命名,即没有使用命名捕获组,那么需要按数字顺序来访问所有捕获组。在只有普通捕获组
  	                                                                   的情况下,捕获组的编号是按照"("出现的顺序,从左到右,从1开始进行编号。
                例:
    */
//	(\d{4})-(\d{2}-(\d\d))
  	/*0:(\d{4})-(\d{2}-(\d\d));1:(\d{4});2:(\d{2}-(\d\d));3:(\d\d)*/
  	/*2. 命名捕获组编号规则:命名捕获组通过显式命名,可以通过组名方便的访问到指定的组,而不需要去一个个的数编号,同时避免了在正则
  	            表达式扩展过程中,捕获组的增加或减少对引用结果导致的不可控。
                      不过容易忽略的是,命名捕获组也参与了编号的,在只有命名捕获组的情况下,捕获组的编号也是按照“(”出现的顺序,从左到右,从1开
                      始进行编号的。
               例:
  	*/
//	(?<year>\d{4})-(?<date>\d{2}-(?<day>\d\d))
  	/*0:(?<year>\d{4})-(?<date>\d{2}-(?<day>\d\d));1:year:(?<year>\d{4});2:date:(?<date>\d{2}-(?<day>\d\d))
      3:day:(?<day>\d\d)  	 
  	 */
  	/*3.普通捕获组与命名捕获组混合编号规则:当一个正则表达式中,普通捕获组与命名捕获组混合出现时,捕获组的编号规则稍显复杂。对于其中的命名捕
  	                                                                            获组,随时都可以通过组名进行访问,而对于普通捕获组,则只能通过确定其编号后进行访问。
  	                                                                            混合方式的捕获组编号,首先按照普通捕获组中“(”出现的先后顺序,从左到右,从1开始进行编号,当普通捕
  	                                                                             获组编号完成后,再按命名捕获组中“(”出现的先后顺序,从左到右,接着普通捕获组的编号值继续进行编号。
  	                                                                            也就是先忽略命名捕获组,对普通捕获组进行编号,当普通捕获组完成编号后,再对命名捕获组进行编号。
  	                                                                            
  	*/
//	(\d{4})-(?<date>\d{2}-(\d\d))
  	/*0:(\d{4})-(?<date>\d{2}-(\d\d));1:(\d{4});3:date:(?<date>\d{2}-(\d\d));2:(\d\d)*/
  	//捕获组的引用
  	/*
  	捕获组引用的分类:1:正则表达式中,对前面捕获组捕获的内容进行引用,称为反向引用;
  				 2:正则表达式中,(?(name)yes|no)的条件判断结构。
  				 3:在程序中,对捕获组捕获内容的引用。
  	 
  	1.反向引用
  	  捕获组捕获到的内容,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用。
  	 作用:用来查找或限定重复,限定指定标识配对出现等等。
  	 引用方式:普通捕获组反向引用:\k<number>,通常简写为\number;
  	                    命名捕获组反向引用:\k<number>或者\k'name'
  	 说明:普通捕获组的反向引用中number是十进制的,即捕获组的编号;命名捕获组反向引用中的name为命名捕获组的组名。
  	2.条件判断表达式
  	  条件判断结构在平衡组中谈到过,基本应用和扩展应用都可以在其中找到例子,这里不再赘述,请参考.NET正则基础之——平衡组。
  	3.程序中引用
  	  根据语言的不同,程序中对捕获组引用的方式也有所不同,下面就JavaScript和.NET进行举例说明。
  	3.1.JavaScript中的引用
  	  由于JavaScript中不支持命名组捕获组,所以对于捕获组的引用就支持普通捕获组的反向引用和$number方式的引用。程序中的引用
  	 一般在替换和匹配时使用。
  	 注:以下应用举例仅考虑简单应用场景,对于<a href="javascript:document.write('<b>hello</b>')"/>这种复杂场景暂不考虑。
  	 3.1.1在replace中引用,通常是通过$number方式引用。
  	        例:替换掉html标签中的属性。
  	*/    
  	/*例:*/
  	var data = "<table id=\"test\"><tr class=\"light\"><td>test</td></tr></table>";
  	var reg = /<([a-z]+)[^>]*>/gi;
  	$("#result").val(data.replace(reg,"<$1>"));
  	/*
  	 3.1.2:在匹配时的引用,通常通过RegExp.$number方式引用。
  	 */
  	/*例:同时获取<img...>中的src和name属性值,属性的顺序不固定。*/
  	var data = ["<img alt='' border='0' name='g6-o44-1' onload='DrawImage' src='/bmp/foo1.jpg' />",
  	            "<img src='/bmp/foo2.jpg' alt='' border='0' name='g6-o44-2' onload='DrawImage'>"];
  	var reg =  /<img\b(?=(?:(?!name=).)*name=(['"]?)([^'"\s>]+)\1)(?:(?!src=).)*src=(['"]?)([^'"\s>]+)\3[^>]*>/i
	var str="";
	for(var i=0;i<data.length;i++)
	{
		var s = data[i];
		str += "原字符串:" + s +"\n";
		if(reg.test(s))
		{
			str += "name:" + RegExp.$2 +"\n";
			str += "src:" + RegExp.$4 +"\n";
			$("#result").val(str);
		}
	}
	/*2.3.2 .NET中的引用(略)
	        (链接:https://www.cnblogs.com/pmars/archive/2011/12/30/2307507.html)
	*/
	/*
	 接上正文:
	上例当把字符串传入exec()方法中之后,发现了一个匹配项。因为整个字符串本身与模式匹配,所以返回的数组matchs的index属性为0。
	数组中的第一项是匹配的整个字符串,第二项包含与第一个捕获组匹配的内容,第三项包含与第二个捕获组匹配的内容。
	对于exec()方法而言,即使在模式中设置了全局标志(g),它每次也只会返回一个匹配项。在不设置全局标志的情况下,在同一个字符串上多
	次调用exec()将始终返回第一个匹配项的信息。而在设置全局标志的情况下,每次调用exec()则都会在字符串中继续查找新匹配项,如下面
	的例子:
	 */
	var text = "cat, bat, sat, fat";
	var pattern1 = /.at/;
	var matches = pattern1.exec(text);
	console.log(matches.index);//0
	console.log(matches[0]);//cat
	console.log(pattern1.lastIndex);//0
	matches = pattern1.exec(text);
	console.log(matches.index);//0
	console.log(matches[0]);//cat
	console.log(pattern1.lastIndex);//0
	
	var pattern2 = /.at/g;
	var matches = pattern2.exec(text);
	console.log(matches.index);//0
	console.log(matches[0]);//cat
	console.log(pattern2.lastIndex);//3
	var matches = pattern2.exec(text);
	console.log(matches.index);//5
	console.log(matches[0]);//cat
	console.log(pattern2.lastIndex);//8
	/*
	 这个例子中的第一个模式pattern1不是全局模式,因此每次调用exec()返回的都是一个匹配项("cat").而第二个模式pattern2是全局模式
	 ,因此每次调用exec()都会返回字符串中的下一个匹配项,直至搜索到字符串末尾为止。此外,还应该注意模式lastIndex属性的变化情况。在
	 全局匹配模式下,lastIndex的值在每次调用exec()后都会增加,而在非全局模式下则始终保持不变。
	 注:IE的JavaScript实现在lastIndex属性上存在偏差,即使在非全局模式下,lastIndex属性每次也会变化。
	 */
	/*
	 test():它接受一个字符串参数。返回Boolean
	 		使用情况:只想知道目标字符串与某个模式是否匹配,但不需要知道其文本内容。该方法经常用在if语句中(经常用来验证用户
	 		输入是否有效)。
	 	例:
	 */
	var text = "000-00-0000";
	var pattern = /\d{3}-\d{2}-\d{4}/;
	if(pattern.test(text)){
		console.log("The pattern was matched");
	};
	//RegExp 继承的toLocaleString()和toString()
	/*
	 返回值:都返回正则表达式的字面量,与创建正则表达式的方式无关。
	 例:
	 */
	var pattern = new RegExp("\\[bc\\]at","gi");
	console.log(pattern.toString());
	console.log(pattern.toLocaleString());
	console.log(pattern.valueOf());
	var pattern = /\[bc\]at/gi;
	console.log(pattern.toString());
	console.log(pattern.toLocaleString());
	console.log(pattern.valueOf());
	/*
	 通过RegExp构造函数方式和字面量方式创建的模式,但是这两种方法仍然会像它是以字面量形式创建的一样显示其字符串表示。
	 注:正则表达式的valueOf方法返回正则表达式本身。
	 */
	// RegExp构造函数属性(这些属性不易对应测试出来)
	/*
	 构造函数属性分类:长属性名              短属性名        说明
	              input       $_       最近一次要匹配的字符串。Opera未实现
	              lastMatch   $&       最近一次的匹配项。Opera未实现
	              lastParen   $+       最近一次匹配的捕获组。Opera未实现
	              leftContext $`       input字符串中lastMatch之前的文本
	              rightContext$'       input字符串中lastMatch之后的文本
	              multiline   $*       布尔值,表示是否所有表达式都使用多行模式。IE和Opera未实现其属性
	 */
	/*
	 注:这些属性适用于作用域中的所有正则表达式,并且基于所执行的最近一次正则表达式操作而变化。
	   使用这些属性可以从exec()或test()执行的操作中提取出更具体的信息。
	   例:
	 */
	var text = "this has been a short summer";
	var parttern = /(.)hort/g;
	if(parttern.test(text)){ 
		console.log(RegExp.input);
		console.log(RegExp.lastMatch);
		console.log(RegExp.leftContext);
		console.log(RegExp.rightContext);
		console.log(RegExp.multiline);
		console.log(RegExp.lastParen);
	};
	/*
	 以上代码创建了一个模式,匹配任何一个字符后跟hort,而且把第一个字符放在了一个捕获组中。
	注:如前所述,例子使用的长属性名都可以用相应的短属性名来代替。只不过,由于这些短属性名大都不是有效的ECMAScript标识符,因此必须
	   通过方括号语法来访问它们。
	 例:
	 console.log(RegExp.$_);
	 console.log(RegExp.["$`"]);
	 console.log(RegExp.["$'"]);
	 console.log(RegExp.["$&"]);
	 console.log(RegExp.["$+"]);
	 console.log(RegExp.["$*"]);
	 */
	/*
	 存储捕获组的9个构造函数属性
	          访问这些属性的语法是:RegExp.$1、RegExp.$2、RegExp.$3、.....RegExp.$9,分别用于存储第一,第二,、、、,第九个匹配
	          的捕获组。在调用exec()和test()方法时,这些属性会被自动填充。
	例:
	 */
	var text = "this has been a short summer";
	var pattern = /(..)or(.)/g;
	if(pattern.test(text)){
		console.log(RegExp.$1);
		console.log(RegExp.$2);
	}
	//模式的局限性
	/*
	尽管ECMAScript中的正则表达式功能还是比较完备的,但仍然缺少某些语言(特别是Perl)所支持的高级正则表达式特性。下面列出了ECMAScript
	正则表达式不支持的特性。(了解更多:www.regular-expression.info)
	  匹配字符串开头和结尾的\A和\Z锚
	 向后查找(lookbehind)
	 并集和交集
	 原子组(atomic grouping)
	 Unicode支持(单个字符除外 ,如\uFFFF)
	 命名的捕获组
	 s(single,单行 )和X(free-spacing,无间隔)匹配模式
	 条件匹配
	 正则表达式注释
	 注:但支持以插入符号(^)和美元符号($)来匹配字符串的开始和结尾;
	         但完全支持向前查找
	         但支持编号的捕获组
	*/
	</script>
</html>
复制代码

转载于:https://juejin.im/post/5affd85951882567096178e1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值