JavaScript中的正则表达式

本文由simon4545根据的《Using Regular Expressions In Javascript (A General Overview)》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.bennadel.com/blog/1742-Using-Regular-Expressions-In-Javascript-A-General-Overview-.htm,以及作者相关信息

——作者:

——译者:simon4545

我爱正则表达式。我发现几乎没有一天我不在使用它们解决一些问题。虽然我爱他们,但是,在使用中一直感觉到有点吃力。我认为这只是因为我没有对它有一个全面的深入了解。因此,我想我会花几分钟给自己(和有兴趣的其他人)一个简短的介绍。

String的replace方法(字符替换)

在JavaScript中,每一个字符串对象有一个replace()方法。这replace()方法可心使用一个正则表达式对象作为第一个参数,可以是一个静态的字符串或一个函数作为第二个参数。当调用replace()方法时,传入一个字符串,原字符串中所有与正则匹配的字符都会被替换成这个字符串:

// -- String.replace() -------------------------------------- //

// Create a test string.
var value = "Hey Tricia, how's it going?";

// The replace() method can take a static replacement string as
// the second argument. Replace the name Tricia with the name
// Joanna.
var newValue = value.replace(
    new RegExp( "\\bTricia\\b", "gi" ),
    "Joanna"
);

// Output the new string.
document.write( newValue );

这里,我们找到所有的"Tricia"并替换成"Joanna"。

当我们运行上面的代码,我们可以得到这样的结果:

Hey Joanna, how's it going?  

这里传入的是一个静态的字符串,但它可以具有一些动态的特性。通过匹配模式的捕获组功能,替换字符串可以由多部分的匹配共同组成。在正则表达式模式下,每个捕获组可以在替换字符串中使用$N来标记,在这里N是捕获组在正则表达示中的索引位置。

// -- String.replace() -------------------------------------- //
 
// Create a test string.
var value = "Hey Tricia, how's it going?";
 
// The replace() method can take a static replacement string as
// the second argument. This static string can contain references
// to captured groups in the pattern. Replace the name Tricia
// with the name hottest Tricia.
var newValue = value.replace(
new RegExp( "\\b(Tricia)\\b", "gi" ),
"hottest $1"
);
 
// Output the new string.
document.write( newValue );

在这个示例中,我们用"hottest $1"来替换"Tricia"。由于$1指向第一个捕获组匹配的值,运行这段代码,我们可以得到这样的结果:

Hey hottest Tricia, how's it going?

在这里你可以看到"hottest $1" 被替换成了"hottest Tricia".

String的replace方法(函数替换)

通过传入上例中的字符串是一种很方便也节省时间的方法,但如果我们想要更多的干预替换的行为,我们可以传入一个方法体来实现。这是一个我个人很喜欢同时也经常 使用的小技巧。每次匹配规则作用于源字符串时都会执行一次这个方法.源字符中被匹配的字符及每个捕获组都会作为特有的参数传入方法内。源字符中与正则匹配的部分会被这个方法的return值替换。

// -- String.replace() -------------------------------------- //
 
// Create a test string.
var value = "Hey Tricia, how's it going?";
 
// The replace() method can take a method as the second argument.
// In this case, the return value of the method is what is
// replaced into the string. The first argument passed to this
// method is the matched pattern; each subsequent argument is a
// captured group from the pattern.
var newValue = value.replace(
new RegExp( "\\b(\\w+)'(s)\\b", "gi" ),
 
// This method will handle the replacement. In this case,
// the $1 is the \\w+ and the $2 is the s.
function( $0, $1, $2){
// Replace in "is".
return( $1 + " is" );
}
);
 
// Output the new string.
document.write( newValue );

通过上例你可以看到所有减写的is都会被替换成标准写法,我们可以得到如下结果:

Hey Tricia, how is it going?

String的match方法(非全局匹配)

JavaScript中,我们还可以使用match方法来收集被匹配的值.match方法可以生成并返回一个源字符中所有与正则匹配的值的数组(译者注:如果可以找到匹配)。

值得一说的是,在match方法里使用全局匹配标签g与否会产生不行的行为效果。

当我们未传入全局匹配的g标签时,match方法会返回一个包含一个该正则完整匹配的字符及其后仍次的子分组匹配字符的数组

// -- String.match() ---------------------------------------- //
 
// Create a test string.
var value = "aabbccddee";
 
// Get the matches in the string. When this is run WITHOUT the
// global flag, it returns the entire match, and then each
// captured group as a subsequent match index.
var matches = value.match(
new RegExp(
"/(\w)(\1)+/i",
"i"
)
);
 
// Output the array of matches.
console.log( matches );

上例的目地是为了找到一个或多个有重复字母的字符串。在这里并没有使用全局匹配g,该正则的语法解释是 \w匹配字母,\1匹配第一个子分组,既(\w)。

我们可以得到这样的结果。

aabbccddee,a,a

(译者注,该文原先的正则使用了不分配分组,并且和下文的全局匹配无法统一,为了便于理解,译者把该正则写法统一了,以便下文中对全局匹配区分)

在这里,aabbccddee即是上文提到的"该正则完整匹配的字符",而"a","a"则是"其后仍次的子分组匹配字符"

注意: 当正则表达式没有发现匹配, match会返回 null ,而不是空数组.  

String的match方法(全局匹配)

当我们传入全局匹配的g标签时,match方法会返回包含所有该正则匹配的字符串的数组而不会包含任何子分组的匹配

// -- String.match() ---------------------------------------- //
 
// Create a test string.
var value = "aabbccddee";
 
// Get the matches in the string. When this is run WITH the
// global flag, it returns a single pattern match in each of the
// array indexes (regardless of capturing).
var matches = value.match(/(\w)(\1)+/ig);
 
// Output the array of matches.
console.log( matches );

当我们执行上述代码,我们可以得到:

aa,bb,cc,dd,ee

各位可以看到,每个(\w)(\1)+所匹配的字符串都会作为match方法返回的数组中的一个元素,这里不会再包含任何对子分组的匹配。

String的search方法

字符串search()方法和indexof()方法很类似,但使用正则表达式。

这个方法只需要传入一个正则表达式,执行后返回第一个匹配的索引,或-1(如果没有发现匹配)

// -- String.search() --------------------------------------- //
 
// Create a test string.
var value = "Kate, you are looking very hot!";
 
// Search for a value in the string. Returns index or -1.
console.log(value.search( new RegExp( "are", "i" ) ) +"<br />");

// Search for a value NOT in the string. Returns index or -1.
console.log(value.search( new RegExp( "fun", "i" ) ) +"<br />");

在上例中我们准备了一个能够匹配源字符串的正则及一个无法匹配的正则,运行这段代码,我们可以得到

10
-1

可以发现,are在源字符串的索引10位置,而fun无法被匹配上,返回-1

RegExp的test方法

正则表达式test()方法只会根据给定的源字符串是否能匹配正则表达式而返回true或false:

// -- RegExp.test() ----------------------------------------- //
 
// Create a test string.
var value = "Kate, you are looking very hot!";
 
// Create a testing pattern.
var pattern = new RegExp( "\\bhot\\b", "i" );
 
// Test to see if the given string matches the given expression.
// Return TRUE or FALSE.
console.log(pattern.test( value ));

当我们执行上面的代码,可以得到:

true

可以看出,该正则能够匹配给定的源字符串。有一点需要重点提示:test方法并不需要该正则完整的匹配源字符串才行。如果你需要正则能完整的匹配源字符串才返回true,那需要在正则的前后加上^和$标记.

RegExp的exec方法

exec方法允许我们收集收集被匹配的值;但是,和String的match方法不同的是exec方法允许我们更深入每一次正则匹配的过程。exec方法可以让我们遍历每一次正则匹配的子字符串。在每一次匹配的回调事件中,我们不但可以到得被匹配的字符串的值及其索引,还可以得到每个子分组的匹配结果。

// -- RegExp.exec() ----------------------------------------- //
 
// Create a test string.
var value = "aabbccddee";
 
// Create a pattern to find the doubled characters.
var pattern = new RegExp( "((\\w)\\2)", "gi" );
 
// Use exec() to keep looping over the string to find the
// matching patterns. NOTE: Since we are using a loop, you MUST
// use the global flag "g", otherwise, this will cause an
// infinite loop to occur.
while (matches = pattern.exec( value )){
 
console.log( matches + "
" );
 
}

执行上面的代码,可以得到下面的结果:

aa,aa,a
bb,bb,b
cc,cc,c
dd,dd,d
ee,ee,e

上面的例子中,我们不但可以得到每个匹配的重复字符串,还可以通过子分组匹配到重复字符串中的每一个字符。

可以看出来,exec方法可以让我们得到String的match的能力同时,还具有更深入String的replace方法的能力。与此同时,exec方法,还可以更有用处:看看它是如何更新RegExp实例的http://www.bennadel.com/blog/697-Javascript-Exec-Method-For-Regular-Expression-Matching.htm

这篇文章并不是想深入JavaScript中每个正则表达式的用法,只是做一个全面的介绍。就像我上文中提到,正则表达示是极好的,我只是想有一个更全面的了解。

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

关于二指禅@冬天

网名"simon4545",微博名:二指禅@秋天。95年接触电脑,98年接触互联网,2008年之前涉及广泛,Flash MTV开发,美工,视频广告。之后走入JSer行业,曾就职于企鹅公司,现为科大讯飞前端架构师。正努力培养自已能够驾驭现有各种平台以及未来可能会直接面向终端用户的各种媒介的表现层能力,将前瞻性与创新能力更好的结合。期待的一天:全息成像代替各种显示设备成为人类与机器的沟通媒介,我那时会做什么...

如需转载,烦请注明出处:

英文原文:http://www.bennadel.com/blog/1742-Using-Regular-Expressions-In-Javascript-A-General-Overview-.htm

中文译文:http://www.w3cplus.com/js/1742-Using-Regular-Expressions-In-Javascript-A-General-Overview.html

返回顶部