js中两种定义正则表达式的方式,1)/这则表达式/;2)new RegExp(’字符串’);ECMAScript3规范规定,一个正则表达式直接量会在执行到它时转换为一个RegExp对象,同一段代码所表示正则表达式直接量会在执行到时转换为一个RegExp对象,同一段代码所表示正则表达式直接量的每次运算都会返回同一个对象。ECMAScript5规范则做了相反的规定,同一段代码所表示的正则表达式直接量的每次原酸都返回新对象。IE一直都是按照ECMAScript5规范实现的,多数新版本浏览器也开始遵循ECMAScript5,尽管目前该标准并未全面广泛推行eg:下面这段代码在Firefox3.6和Firefox4+中运行结果不一致
function getRE(){
var re=/[a-z]/;
re.foo=”bar”;
return re;
}
var reg=getRE(),re2=getRE();
console.log(reg==re2);//在Firefox3.6中返回true,在FireFox4+中返回false
reg.foo=”baz”;
console.log(re2.foo);//在FireFox3.6中显示“baz”,在FireFox4+中显示“bar”
原因是:在ECMAScript3规范中,用正则表达式哈创建的RegExp对象会共享同一个实例,而在ECMAScript5中则是两个独立的实例。
2.正则表达式基础详见博客:http://7613577.blog.51cto.com/7603577/1531057
3.字符类:将直接量字符单独放进括号内就组成了字符类。一个字符类可以匹配它所包含的任意字符。因此,正则表达式/[abc]/就和字母a,b,c中的任意一个匹配。另外,可以通过“^”符号来定义否定字符类,它匹配所有不包含在方括号内的字符。定义否定字符类时,将一个“^”符号作为方括号内的第一个字符。正则表达式/[^abc]/匹配的是“a”,“b”,“c”之外的所有字符。字符类可以使用连字符来表示字符范围。要匹配拉丁字母中的小写字母可以使用/[a-z]/,要匹配拉丁字母表中任何字母和数字,则使用/[a-zA-Z0-9]/.
4.*:表示匹配前一项0次,或多次,等价于{0,}
5.非贪婪模式:普通的正则表达式匹配重复字符是尽可能多的匹配,而且允许后续的正则表达式继续匹配。因此我们称之为“贪婪的”匹配。我们同样可以使用正则表达式进行非贪婪匹配。只须在待匹配的字符后跟随一个问号即可:“??”、“+?”、“*?”或“{1,5}?”。比如,正则表达式/a+/可以匹配一个或多个连续的字母a。当使用“aaa”作为匹配字符串时,正则表达式会匹配它的三个字符。但是/a+?/也可以匹配一个或多个连续字母a,但它是尽可能少地匹配。我们同样将“aaa”作为匹配字符串,但后一个模式只能匹配第一个a
使用非贪婪的匹配模式所得到的结果可能和期望并不一致。考虑一下正则表达式/a+b/,它可以匹配一个或多个a,以及一个b。当使用“aaab”作为匹配字符串时,它会匹配整个字符串。现在再试一下非匹配的版本/a+?b/,它匹配尽可能少的a和一个b。当用它来匹配“aaab”时,你期望它能匹配一个a和最后一个b。但实际上,这个模式却匹配了整个字符串,和该模式的贪婪匹配模式一模一样。这是因为正则表达式的模式匹配总是会寻找字符串中第一个可能匹配的位置。由于该匹配是从字符串的第一个字符开始的,因此在这里不考虑它的子串中更短的匹配。
6.选择、分组和引用:正则表达式的语法还包括指定选择项、字表达式分组和引用前一子表达式的特殊字符。字符“|”用于分割供选择的字符。例如,/ab|cd|ef/可以匹配字符串“ab”,还可以匹配字符串“cd”,还可以匹配字符串“ef”。/\d{3}|[a-z]{4}/匹配的是三位数字或者四个小写字母。
注意,选择项的尝试匹配次序是从左到右,直到发现了匹配项。如果左边的选择项匹配,就忽略右边的匹配项,即使它产生更好的匹配。因此,当正则表达式/a|ab/匹配字符串“ab”时,它只能匹配第一个字符。
正则表达式中的圆括号有多种作用,一个作用是把单独的项组合成子表达式,以便可以像处理一个独立的单元那样用“|”、“*”,“+”或者“?”等来对单元内的项进行处理。例如,/java(script)?/可以匹配字符串“java”,其后可以有“script”也可以没有。
在正则表达式中,圆括号的另一个作用是在完整的模式中定义子模式。当一个正则表达式成功地和目标字符串相匹配时,可以从目标串中抽出和圆括号中的子模式相匹配的部分,例如,假定我们正在检索的模式是一个或多个小写字母后面跟随了以为或多位数字,则可以使用模式/[a-z]+\d/。但假定我们真正关心的是每个匹配尾部的数字,那么如果将模式的数字部分放在括号中(/[a-z]+(\d+)/,就可以从检索到的匹配中抽取数字了,之后我们会有详细的解释。
带圆括号的表达式的另一个用途是允许在同一正则表达式的后部引用前面的子表达式。这是通过在字符“\”后加一位或多位数字来实现的。这个数字指定了带圆括号的子表达式在正则表达式中的位置。例如,\1引用的是第一个带圆括号的子表达式,\3引用的是第三个带圆括号的子表达式。注意,因为子表达式可以嵌套另一个子表达式,所以它的位置是参与计数的左括号的位置。例如,在下面的正则表达式中,嵌套的子表达式([Ss]cript)可以用\2来指代
/([Jj]ava([Ss]cript)?)\sis(fun\w*)/
对正则表达式中前一个子表达式的引用,并不是指对子表示模式的引用,而指的是与那个模式相匹配的文本的引用。这样,引用可以用于实施一条约束,即一个字符串各个单独部分包含的完全相同的字符。例如,下面的正则表达式匹配的就是位于单引号或双引号之内的0个或多个字符。但是,它并不要求左侧和右侧的引号匹配(即,加入的两个引号都是单引号或都是双引号):
/[‘”][^’”]*[‘”]/
如果要匹配左侧和右侧的引号,可以使用如下引用:
/([‘”])[^’”]*\1/
\1匹配的是第一个带圆括号的子表达式所匹配的模式。在这个例子汇总,存在这样一条约束,那就是左侧的引号必须和右侧的引号相匹配。正则表达式不允许用双引号括起来的内容中有单引号,反之亦然。即上式不匹配字符串abc”afdd’f”中的任何部分。即不能在字符类中使用这种引用,所以下面的写法是非法的:
/([‘”])[^\1]*\1/
在后面的内容中,我们会看到一种带圆括号的子表达式的引用,这是正则表达式的检索和替换操作的强大特性之一。
同样,在正则表达式中不用创建带数字编码的引用,也可以对子表达式进行分组。它不是以“(”和“)”进行分组,而是以“(?:”和“)”来进行分组,比如考虑下面这个模式:
/([Jj]ava(?:[Ss]cript)?)\sis\s(fun\w*)/
这里,子表达式(?:[Ss]cript)仅仅用于分组,因此复制符号“?”可以应用到各个分组。这种改进的圆括号并不生成引用,所以在这个正则表达式中,\2引用了与(fun\W*)匹配的文本。
7.小结:
1)|,选择,匹配的是该符号左边的子表达式或右边的子表达式;
2)(…)组合,将几个项组合为一个单元,这个单元可通过”*”,”+”,”?”和”|”等符号加以修饰,而且可以记住和这个组合相匹配的字符串以供此后的引用使用;
3)(?:…)只组合,把项组合到一个单元,但不记忆与该组相匹配的字符;
4)\n和第n个分组第一次匹配的字符相匹配,组是圆括号中的子表达式(也可以是嵌套的),组索引是从左到右的左括号数,“(?:”形式的分组不编码。
8.指定匹配位置:正则表达式中的多个元素才能够匹配字符串的一个字符。例如,\s匹配的只是一个空白符。还有一些正则表达式的元素匹配的是字符之间的位置,而不是实际的字符。例如,\b匹配一个单词的边界,即位于\W(ASCII单词)字符和\W(非ASCII单词)之间的边界,或位于一个ASCII单词与字符串的开始或结尾之间的边界。像\b这样的元素不匹配某个可见的字符,他们制定匹配发生的合法位置。有时我们称这些元素为正则表达式的锚,因为他们将模式定位在搜索字符串的特定位置上。最常用的锚元素是^,它用来匹配字符串开始,锚元素$用来匹配字符串的结束。
例如要匹配单词“JavaScript”,可以使用正则表达式/^JavaScript$/。如果想匹配“Java”这个单词本身(不像在“JavaScript”中作为单词的前缀),可以使用正则表达式/\sJava\s/,可以匹配前后都有空格的单词“Java”。但是这样做有两个问题,第一,如果“Java”出现在字符串的开始或结尾,就匹配不成功,除非开始和结尾各有一个空格。第二个问题是,当找到了与之匹配的字符串时,它返回的匹配字符串的前端和后端都有空格,这并不是我们想要的。因此我们使用单词的边界\b来代替真正的空格符\s进行匹配(或定位)。这样正则表达式就写成了/\bJava\b/。元素\B将把匹配的锚点定位在不是单词的边界之处。因此,正则表达式/\B[Ss]cript/与“JavaScript”和“postscript”匹配,但不与”script”和“Scripting”匹配。
任意正则表达式都可以作为锚点条件。如果在符号“(?=”和“)”之间加入一个表达式,他就是一个先行断言,用以说明圆括号内的表达式必须正确匹配,但并不是真正意义上的匹配。比如,要匹配一种常用的程序设计语言的名字,但只在其后有冒号时才匹配,可以使用/[Jj]ava([Ss]cript)?(?=\:)/,此处最后一个\可以没有。这个正则表达式可以匹配“JavaScript:The Definitive Guide”中的“JavaScript”,但是不能匹配“Java in a Nutshell”中的“Java”,因为它后面没有冒号。
带有“(!”的断言是负向先行断言,用以指定接下来的字符都不必匹配。例如,/Java(?!Script)([A-Z]\w*)/可以匹配“Java”后跟随一个大写字母和任意多个ASCII单词,但Java后不能跟随“Script”。它可以匹配“JavaBeans”,但不能匹配“Javanese”,它可以匹配“JavaScriapt”,但不能匹配“JavaScripter”。
9.小结:
1)^,匹配字符串的开头,在多行检索中,匹配一行的开头
2)$,匹配字符串的结尾,在多行检索中匹配一行的结尾
3)\b,匹配一个单词的边界,简而言之,就是位于字符\w和\W之间的位置,或位于字符\w和字符串的开头或者结尾的位置(但需要注意,[\b]匹配的是退格符)
4)\B,匹配非单词边界的位置
5)(?=p),零宽正向先行断言,要求接下来的字符都与p匹配,但匹配结果不包括匹配p的那些字符
6)(?!p),零宽负向先行断言,要求接下来的字符不与p匹配
10.修饰符:用以说明高级匹配模式的规则。修饰符是放在“/”之外的,也就是说,它们不是出现在两条斜线之间,而是第二条斜线之后。JavaScript支持三个修饰符,修饰符“i”用以说明模式匹配不区分大小写的。修饰符“g”说明模式匹配应该是全局的,也就是说,应该找出被检索的字符串中所有的匹配。修饰符“m”用以在多行模式中执行匹配,在这种模式下,如果待检索的字符串包含多行,那么^和$锚字符除了匹配整个字符串的开始和结尾之外,还能匹配每行的开始和结尾。比如正则表达式/java$/im可以匹配“java”也可以匹配“Java\nis fun”,(\n表示换行)。
这些修饰符可以任意组合,比如,要想不区分大小写匹配字符串中的第一个单词“java”(“Java”或“JAVA”等)。可以使用不区分大小写的修饰符来定义正则表达式/\bjava\b/i。要想匹配字符串中所有的单词,则需要添加修饰符g:/\bjava\b/gi。
11.小结:
1)i,执行不区分大小写的匹配
2)g,执行一个全局匹配,简言之,即找到所有的匹配,而不是在找到第一个之后就停止
3)m,多行匹配模式,^匹配一行的开头和字符串的开头,$匹配行的结束和字符串的结束
12.search():它的参数是一个正则表达式,返回第一个与之匹配的子串的起始位置,如果找不到匹配的子串,它将返回-1。如果search()的参数不是正则表达式,则首先会通过RegExp构造函数将它转换成正则表达式,search()方法不支持全局检索,因为它忽略正则表达式参数中的修饰符g。eg:
“JavaScript”.search(/script/i);//返回4
13.replace()方法用以检索与替换操作。其中第一个参数是一个正则表达式,第二个参数是要进行替换的字符串。这个方法会对调用它的字符串进行检索,使用指定的模式来匹配。如果正则表达式中设置了修饰符g,那么源字符串中所有与模式匹配的子串都将替换成第二个参数指定的字符串而不是正则表达式,则replace(0将直接搜索这个字符串,而不是像search()一样首先通过RegExp()将它转换为正则表达式。比如,乐意使用下面方法,利用replace()将文本中的所有javascript(不区分大小写)统一替换为“JavaScript”:
text.replace(/javascript/gi,”JavaScript”);//将所有不区分大小写的javascript都替换成大小写正确的JavaScript
但replace()的功能远不止这些,前面提到,正则表达式中使用圆括号括起来的子表达式是带有从左到右的索引编号的,而且正则表达式会记忆与每个子表达式匹配的文本。如果在替换字符串中出现了$加数字,那么replace()将用与指定子表达式相匹配的文本来替换这两个字符。这是一个非常有用的特性。比如,可以用它将一个字符串中的英文引号替换为中文半角引号:
//一段引用文本起始于引号,结束于引号
//中间的内容区域不能包含引号
var quote=/”([^”]*)”/g;
//用中文半角引号替换英文引号,同时要保持引号之间的内容(存储在$1中)没有修改
text.replace(quote,’”1”’);
replace()方法还有一些其他重要特性,其第二个参数可以是个函数,该函数能够动态地计算替换字符串。
14.match():唯一的参数就是一个正则表达式(或通过RegExp()构造函数将其转换为正则表达式),返回的一个由匹配结果组成的数组。如果正则表达式设置了修饰符g,则该方法返回的数组包含字符串中的所有匹配结果。eg:
“1 plus 2 equal 3”.match(/\d+/g);//返回[“1”,”2”,”3”]
如果这个正则表达式没有设置修饰符g,match()就不会进行全局检索,它只检索第一个匹配。但即使match()执行的不是全局检索,它也返回一个数组。在这种情况下,数组的第一个元素就是匹配的字符串,余下的元素则是正则表达式中用圆括号括起来的子表达式。因此,如果match()返回一个数组a,那么a[0]存放的是完整的匹配,a[1]存放的则是第一个圆括号括起来的表达式相匹配的子串,一次类推。为了和方法replace()保持一致,a[n]存放的是$n的内容。eg:
//使用如下的代码来解析一个URL
//http://7613577.blog.51cto.com/7603577/1531057
varurl=/(\w+):\/\/([\w.]+)\/(\S*)/;
vartext="Visit my blog ar http://www.example.com/~david";
varresult=text.match(url);
if(result!=null){
var fullurl=result[0];//包含"http://"
var protocol=result[1];
var host=result[2];
console.log("fullurl="+fullurl);//fullurl=http://www.example.com/~david
console.log("protocol="+protocol);//protocol=p
console.log("host="+host);//host=www.example.com
}
值得注意的是,给字符串的match()方法传入一个非全局的正则表达式,实际上和给这个正则表达式exec()方法传入的字符串时一模一样的,它返回的数组带有两个属性:index和input,接下来对exec()方法的讨论中会提到:
split():这个方法用以将调用它的字符串拆分为一个子串组成的数组,使用的分割符就是split()的参数,例如:
“1,2,3”.split(“,”);//返回[1,2,3]
15.split()方法的参数也可以是一个正则表达式,这使得split()方法异常强大。例如,可以指定分隔符,允许两边可以留有如任意多的空白字符eg:
“1, 2, 3 “.split(/s*,\s*/);//返回[1,2,3]
16.RegExp对象:构造函数带两个字符串参数,其中第二个参数是可选的,RegExp()用以创建新的RegExp对象。第一个参数包含正则表达式的主题部分,也就是正则表达式直接量中两条斜线之间的文本。需要注意的是,不论是字符串直接量还是正则表达式,都使用“\”字符作为转义字符的前缀,因此当给RegExp()传入一个字符串表述的正则表达式时,必须将“\”替换成“\\”。RegExp()的第二个参数是可选的,如果提供第二个参数,他就指定正则表达式的修饰符。不过只能传入修饰符g、i、m或者他们的组合。eg:
//全局匹配字符串中的5个数字,注意这里使用了“\\”,而不是“\”
var zipcode=new RegExp(”\\d{5}”,”g”);
RegExp()构造函数非常有用,特别是在需要动态创建正则表达式的时候,这种情况往往没办法通过写死在代码中的正则表达式直接量来实现。例如待检索的字符串是由用户输入的,就必须使用RegExp()构造函数,在程序运行时创建正则表达式。
16.RegExp的属性:每个RegExp对象都包含5个属性。属性source是一个只读的字符串,包含正则表达式的文本。属性global是一个只读的布尔值,用以说明这个正则表达式是否带有修饰符g。属性ignoreCase也是一个只读的布尔值,用以说明这个正则表达式是否带有修饰符i。属性multiline是一个只读的布尔值,用以说明正则表达式是否带有修饰符m。最后一个属性lastIndex是一个可读可写的整数。如果匹配模式带有g修饰符,这个属性存储在整个字符串下一次检索的开始位置,这个属性会被exec()和test()方法用到。
17.RegExp方法:
1) exec():和String.match()相似,只是RegExp方法参数是一个字符串,而String方法的参数是一个ExgExp对象。exec()方法对一个指定的字符串执行一个正则表达式,简而言之,就是在一个字符串中执行匹配检索。如果它没有找到任何匹配,它就返回null,但如果它找到了一个匹配,它将返回一个数组,就像match()方法为非全局检索返回的数组一样。这个数组的第一个元素包含的是与正则表达式相匹配的字符串,余下的元素时与圆括号内的子表达式相匹配的子串。属性index包含了发生匹配的字符位置,属性input引用的是正在检索的字符串。
和match()方法有所不同,不管正则表达式是否具有全局修饰符g,exec()都会返回一样的数组。回忆一下,当match()的参数是一个全局正则表达式时,它返回由匹配结果组成的数组。相比之下,exec()总是返回一个匹配结果,并提供关于本次匹配的完整信息。当调用exec()的正则表达式对象具有修饰符g时,它将把当前正则表达式对象的lastIndex属性设置为紧挨着匹配子串的字符位置。当同一个正则表达式第二次调用exec()时,它将从lastIndex属性所指示的字符处开始检索。如果exec()没有发现任何匹配结果,它会将lastIndex重置为0(在任何时候都可以将lastIndex属性设置为0,每当在字符串中找到最后一个匹配项后,在使用这个RegExp对象开始新的字符串查找之前,都应将lastIndex设置为0)。这种特殊的行为使我们在使用正则表达式匹配字符串的过程中反复调用exec(),比如:
varpattern=/Java/g;
vartext="JavaScript is more fun than Java!";
varresult;
while((result=pattern.exec(text))!=null){
vartmp="Matched‘"+result[0]+"‘"+" at position ";
tmp+=result.index+";next search beginsat "+pattern.lastIndex;
console.log(tmp);
}
//运行结果:
//Matched‘Java‘ at position 0;next search begins at 4 qwzn1.js:110
//Matched‘Java‘ at position 28;next search begins at 32
2) test():和exec()等价,当exec()的返回结果不是null时,test()返回true。当一个全局正则表达式调用test()时,它的行为和exec()相同,因为它从lastIndex指定的位置处开始检索某个字符串。如果找到了一个匹配结果,那么它就立即设置lastIndex为当前匹配子串的结束位置。这样一来,就可以使用test()来遍历字符串,就想exec()方法一样。
本文出自 “虎哥的博客” 博客,请务必保留此出处http://7613577.blog.51cto.com/7603577/1568318
原文地址:http://7613577.blog.51cto.com/7603577/1568318