首页 » JavaScript » match、search、replace、split

match、search、replace、split

String 类型定义了几个用于在字符串中匹配模式的方法。第一个方法就是match(),在字符串上调用这个方法,本质上与调用RegExp的exec()方法相同。match()方法只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象。来看下面的例子。

var text = "cat, bat, sat, fat";
var pattern = /.at/;

//与pattern.exec(text)相同
var matches = text.match(pattern);
alert(matches.index); //0
alert(matches[0]); //"cat"
alert(pattern.lastIndex); //0

本例中match()方法返回了一个数组;如果是调用RegExp对象的exec()方法并传递本例中的字符串作为参数,那么也会得到与此相同的数组;数组的第一项是与整个模式匹配的字符串,之后的每一项保存着正则表达式中的捕获匹配的字符串。

另一个用于查找模式的方法是search()。这个方法的唯一参数与match()方法的参数相同:由字符串或RegExp对象指定的一个正则表达式。search()方法返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1。而且,search()方法始终是从字符串开头向后查找模式。看下面的例子。

var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
alert(pos); //1

这个例子中的search()方法返回1,即”at”在字符串中第一次出现的位置。

为了简化替换字符串的操作,ECMAScript提供了replace()方法,这个方法接收两个参数:第一个参数可以是一个RegExp对象或者一个字符串(这个字符串不会被转换成正则表达式),第二个参数可以是一个字符串或者一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,唯一的办法就是提供一个正则表达式,而且要指定全局(g)标志,如下所示。

var text = "cat, bat, sat, fat";
var result = text.replace("at", "ond");
alert(result); //"cond, bat, sat, fat"

result = text.replace(/at/g, "ond");
alert(result); //"cond, bond, sond, fond"

在这个例子中,首先传入replace()方法是字符串“at”和替换用的字符串“ond”。替换的结果是把“cat”变成了“cond”,但字符串中的其它字符并没有受到影响。然后,通过将第一个参数修改为带有全局标志的正则表达式,就将全部“at”都替换成了“ond”。

如果第二个参数是字符串,那么还可以使用一些特殊的字符序列,将正则表达式操作得到的值插入到结果字符串中。下表列出了ECMAScript提供的这些特殊的字符序列。

字符序别替换文本
$$$
$&最近一次的匹配项
$`匹配的子字符串之前的子字符串。与RegExp.leftContext的值相同
$’匹配的子字符串之后的子字符串。与RegExp.rightContext的值相同
$n匹配第n个捕获组的子字符串,其中n等于0-9。例如,$1是匹配第一个捕获组的子字符串,$2是匹配第二个捕获组的子字符串,一次类推。如果正则表达式中没有定义捕获组,则使用空字符串
$nn匹配第nn个捕获组的子字符串,其中nn等于01-99。例如,$01是匹配第一个捕获组的子字符串,$02是匹配第二个捕获组的子字符串,以此类推。如果正则表达式中没有定义捕获组,则使用空字符串

通过这些特殊的字符序列,可以使用最近一次匹配结果中的内容,如下面的例子所示。

var text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g, "word ($1)");
alert(result); //word (cat), word (bat), word (sat), word (fat)

在此,每个以“at”结尾的单词都被替换了,替换结果是“word”后跟一对圆括号,而圆括号中是字符序列$1所替换的单词。

replace()方法的第二个参数也可以是一个函数。在只有一个匹配项(即与模式匹配的字符串)的情况下,会向这个函数传递3个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。在正则表达式中定义了多个捕获组的情况下,传递给函数的参数依次是模式的匹配项、第一个捕获组的匹配项、第二个捕获组的匹配项……,但最后两个参数仍然分别是模式的匹配项在字符串中的位置和原始字符串。这个函数应该返回一个字符串,表示应该被替换的匹配项使用函数作为replace()方法的第二个参数可以实现更加精细的替换操作,请看下面的例子。

function htmlEscape(text) {
    return text.replace(/[<>"&]/g, function(match, pos, originalText) {
        switch(match) {
        case "<":
            return "&lt;";
        case ">":
            return "&gt;";
        case "&":
            return "&amp;";
        case "\"":
            return "&quot;";
        }
    });
}
alert(htmlEscape("<p class=\"greeting\">Hello world!</p>"));
//&lt;p class=&quot;greeting&quot;&gt;Hello world!&lt;/p&gt;

这里,我们为插入HTML代码定义了函数htmlEscape(),这个函数能够转义4个字符:小于号、大于号、和号、以及双引号。实现这种转义最简单方式,就是使用正则表达式查找这几个字符,然后定义一个能够针对每个匹配的字符返回特定HTML实体的函数。

最后一个与模式匹配有关的方法是split()、这个方法可以基于指定的分隔符将一个字符串分割成多个字符串,并将结果放在一个数组中。分隔符可以是字符串,也可以是一个RegExp对象(这个方法不会将字符串看成正则表达式)。split()方法可以接收可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小。请看下面的例子。

var colorText = "red,blue,green,yellow";
var colors1 = colorText.split(",");      //["red", "blue", "green", "yellow"]
var colors2 = colorText.split(",", 2);   //["red", "blue"]
var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""]

在这个例子中,colorText是逗号分割的颜色名字符串。基于该字符串调用split(“,”)会得到一个包含其中颜色名的数组,用于分割字符串的分隔符是逗号。为了将数组截短,让它值包含两项,可以为split()方法传递第二个参数2。最后,通过使用正则表达式,还可以取得包含逗号字符的数组。需要注意的是,在最后一次调用split()返回的数组中,第一项和最后一项是两个空字符串。之所以会这样,是因为通过正则表达式指定的分隔符出现在子字符串的开头(即子字符串”red”)和末尾(即子字符串“yellow”)。

对split()中正则表达式的支持因浏览器而异。尽管对于简单的模式没有什么差别,但对于未发现匹配项以及带有捕获组的模式,匹配的行为就不大相同了。以下是几种常见的差别。

  • IE8及之前版本会忽略捕获组。ECMA-262规定应该把捕获组拼接到结果数组中。IE9能正确地在结果中包含捕获组。
  • Firefox 3.6及之前的版本在捕获组未找到匹配项时,会在结果数组中包含空字符串;ECMA-262规定没有匹配项的捕获组在结果数组中应该用undefined表示。

在正则表达式中使用捕获组时还有其它微妙的差别。在使用这种正则表达式时,一定要在各浏览器下多做一些测试。

此文章发表在 JavaScript. 将 固定链接 加入收藏.