7.2 使用字符串
String对象预定义了很多方法,利用这些方法可以灵活处理字符串。字符串操作主要包括:
查找字符,如是否包含数字、字母还是其他特定字符。
查找字符串长度和字符格式,如数组、日期等。
字符串基本操作,如截取子字符串、插入字符、删除字符、置换字符、字符串比较、字符串连接和拆分等。
字符串高级操作,如模糊匹配、字符加密等。
7.2.1 案例:计算字符串长度
String对象预定义了length属性,该属性存储着当前字符串的长度。它可以显示字符串的字符个数。
【示例1】下面的代码使用了字符串的length属性获取字符串的字符长度。
var s="String对象长度"; //定义字符串直接量 alert(s.length); //返回10
字符包括单字节、双字节两种类型,为了精确计算字符串的字节长度,可以采用以下两个方法。
【示例2】利用循环结构枚举每个字符,并根据字符的字符编码,判断当前字符是单字节还是双字节,然后递加字符串的字节数。
String.prototype.lengthB = function( ){ //获取并返回指定字符串的字节数,扩展String对象方法 var b = 0, l = this.length; //初始化字节数递加变量,并获取字符串参数的字符个数 if(l){ //如果存在字符串,则执行计算 for(var i=0; i<l; i++){ //遍历字符串,枚举每个字符 if(this.charCodeAt( i ) > 255 ){ //如果当前字符的编码大于255,说明它是双字节字符 b+=2; //则累加2个 }else{ b++; //否则递加一次 } } return b; //返回字节数 }else{ return 0; //如果参数为空,则返回0个 } }
测试:
var s="String对象长度"; //定义字符串直接量 alert(s.lengthB()) //返回14
【拓展】在检测字符是否为双字节或单字节时,方法也是有多种的,这里再提供两种思路:
for( var i = 0; i < l; i ++ ){ var c=this.charAt(i); //获取当前字符 if ( escape( c ).length > 4 ) { //如果字符的转义序列大于4位,说明是双字节 b += 2; }else if( c ! = "\r" ) { b ++ ; } }
或者使用正则表达式进行字符编码验证:
for( var i = 0; i < l; i ++ ){ var c = this.charAt( i ); if ( /^[\u0000-\u00ff]$/.test(c) ) { //其中/^[\u0000-\u00ff]$/表示正则表达式,匹配单字节字符 b ++ ; }else { b += 2; } }
【示例3】利用正则表达式把字符串中双字节字符临时替换为两个字符,然后调用length属性获取临时字符串的长度:
String.prototype.lengthB = function(){ var s = this.replace( /[^\x00-\xff]/g, "**" ); return s.length; }
上述方法比较简洁,但是执行效率相对要慢,因为它需要两次遍历字符串,即调用replace()方法一次,使用length属性时一次。而第一种方法中只进行一次字符串遍历。
注意:String对象的length属性是只读属性,这与Array的length属性不同(即数组的长度是可以动态改变的)。不过,又与数组一样,字符串可以使用下标来定位单个字符在字符串中的位置,其中第一个字符的下标值为0,最后一个字符的下标值为length-1。但是字符串中的字符是不能够被for/in循环枚举的。运算符delete也不能删除字符串中指定位置的字符。
7.2.2 案例:连接字符串
为一个字符串添加字符串的方法也很多。最简单的是使用加号运算符,把多个字符串或字符连接在一起。
【示例1】下面的代码使用了加号运算符连接两个字符串。
var s1 = "abc"; var s2 = "def"; alert(s1+s2); //字符串连接,返回字符串"abcdef"
String对象定义了concat()方法,该方法可以把多个参数添加到指定字符串的尾部。不过,在实际开发中,直接使用加号运算符执行字符串连接操作通常更简便一些。
【示例2】下面的代码使用了字符串的concat()方法将多个字符串连接在一起。
var s1 = "abc"; var s2=s1.concat("d", "e", "f"); //调用concat()连接字符串 alert(s2); //返回字符串"abcdef"
concat()方法的参数是没有限制的,参数类型也没有限制。如果需要,在执行连接操作时,它会把所有参数都转换为字符串,然后按顺序连接到当前字符串的尾部,最后返回连接后的字符串。当然,concat()方法不会修改原字符串的值。这与数组的concat()非常相似,操作也一样。
7.2.3 案例:查找字符串
检索字符串、查找特定字符串是字符串操作中的基本技能,实际开发中大量工作也是与此有关的,如表单验证、查找指定字符等。为此,String对象定义了很多功能强大的方法,详细说明如表7-1所示。
表7-1 String对象的查找字符串方法
1.获取指定位置的字符
使用String的charAt()和charCodeAt()方法,可以根据参数返回指定下标位置的字符或字符的编码。
【示例1】使用charAt()把字符串中每个字符都装入一个数组中,从而可以为String对象扩展一个原型方法,用来把字符串转换为数组。
String.prototype.toArray=function(){ //把字符串转换为数组 var l=this.length, a=[]; //获取当前字符串长度,并定义空数组 if(l){ //如果存在则执行循环操作 for(var i=0; i<l; i++){ //遍历字符串,间接枚举每个字符 a.push(this.charAt(i)); //把每个字符按顺序装入数组 } } return a; //返回数组 }
然后就可以实现对字符串的所有字符进行遍历。
var s="abcdefghijklmn".toArray(); //把字符串转换为数组 for(var i in s){ //遍历被转换的字符串,并枚举每个字符 alert(s[i]); }
对于charAt()方法来说,字符串中第一个字符的下标值为0。如果参数n不在0和length-1之间,则返回空字符串。
字符实际上也是字符串,即长度为1的字符串。JavaScript没有定义字符类型的数据,而在其他强类型语言中,是把字符和字符串分为两种不同类型的数据。
charCodeAt()与charAt()方法操作一样,不过它返回的是指定位置的字符编码。如果指定下标值为负数,或者大于等于字符串的长度,则该方法将返回NaN,而不再是0。
2.查找子字符串的位置
charAt()和charCodeAt()方法是根据下标查找字符,而indexOf()和lastIndexOf()方法则是根据指定字符串查找它的下标位置。
indexOf()方法有两个参数,第一个参数为一个子字符串,是指将要查找的对象。第二个参数为一个整数值,用来指定查找的起始位置,其取值范围是0~length-1,对于该参数来说:
如果值为负数,则视为0,就相当于从第一个字符开始查找。
如果省略了这个参数,也将从字符串的第一个字符开始查找。
如果值大于等于length属性值,则视为当前字符串中没有指定的子字符串,即返回-1。不过在JavaScript 1.0和JavaScript 1.1中会返回一个空字符串(这是一个Bug)。
【示例2】下面的代码查询了字符串中首个字母a的下标位置。
var s = "javascript"; var i = s.indexOf("a", -10); alert(i); //返回值为1,即字符串中第二个字符
indexOf()方法只返回查找到的第一个子字符串的起始下标值,如果没有找到将返回-1。
【示例3】下面的代码查询了URL字符串中首个字母w的下标位置。
var s = "http://www.mysite.cn/"; var a=s.indexOf("www"); //返回值为7,即第一个字符w的下标位置
如果要想查找下一个子字符串,则可以使用第二个参数来限定范围。
【示例4】下面的代码分别查询了URL字符串中两个点号字符的下标位置。
var s = "http://www.mysite.cn/"; var b=s.indexOf("."); //返回值为10,即第一个字符.的下标位置 var e=s.indexOf(".", b+1); //返回值为15,即第一个字符.的下标位置
注意:indexOf()方法是按着从左到右的顺序进行查找的。如果希望从右到左来进行查找,则可以使用lastIndexOf()方法来查找。
【示例5】下面的代码以从后往前的方式查询URL字符串中最后一个点号字符的下标位置。
var s = "http://www.mysite.cn/index.html"; var n=s.lastIndexOf("."); //返回值为24,即第三个字符.的下标位置
提示:使用lastIndexOf()方法时,需要注意下面几个问题。
(1)lastIndexOf()方法的查找顺序是从右到左,但是其参数和返回值都是根据字符串的下标从左到右的顺序来计算的,而不是反着来计算字符串的下标值。即字符串的左侧第一个字符下标值始终都是0,而最后一个字符的下标值始终都是length-1。
(2)第二个参数指定起始查找的下标位置,这个起始是指指定下标位置左侧开始查找,因为它是按从右到左的顺序执行的。例如:
var s = "http://www.mysite.cn/index.html"; var n=s.lastIndexOf(".",11); //返回值为10,而不是15
其中第二个参数值11表示字符c(第一个)的下标位置,然后从其左侧开始向左查找,所以就返回第一个点号的位置。
(3)如果查找到,则返回第一次查找的子字符串的起始下标值,这个起始位置是最左侧的意思,而不是最右侧位置。例如:
var s = "http://www.mysite.cn/index.html"; var n=s.lastIndexOf("www"); //返回值为7,而不是10
如果第二个参数出现没有传递,或为负值,或大于等于length属性值等情况,则将遵循indexOf()方法来计算。
3.匹配字符串
search()和match()方法能够查找子字符串。由于它们都与正则表达式紧密联系,所以只有掌握正则表达式的使用之后,才能够灵活使用它们。
search()方法的功能与indexOf()方法相似,都是查找子字符串第一次出现的下标位置。但是它仅有一个参数,即指定的匹配模式,也没有lastIndexOf()的反向检索的功能,同时它也不支持全局模式。
【示例6】下面的代码使用了search()方法匹配斜杠字符在URL字符串的下标位置。
var s = "http://www.mysite.cn/index.html"; var n=s.search("//"); //返回值为5
提示:使用search()方法时需要注意以下几个问题。
(1)该方法的参数为正则表达式,即声明要匹配的RegExp对象。如果该参数不是RegExp对象,则JavaScript会使用RegExp()构造函数把它转换成RegExp对象。
(2)search()方法遵循从左到右的查找顺序,并返回第一个匹配的子字符串的起始下标值。如果没有找到,则返回-1。
(3)该方法没有第二个参数,它无法查找指定的范围,换句话说它始终返回的是第一个匹配子字符串的下标值。从这点上考虑,它没有indexOf()灵活和实用。
【示例7】与search()方法相比,match()方法要强大很多,它能够找出所有匹配的子字符串,并存储在一个数组中返回。
var s = "http://www.mysite.cn/index.html"; var a=s.match(/h/g); //全局匹配所有字符h alert(a); //返回数组[h, h]
【拓展】match()方法的用法也比较灵活,由于需要一定的正则表达式基础,下面介绍该方法应该注意的问题。
(1)match()方法返回的是一个数组,但是它的行为受正则表达式的匹配模式限制,如果匹配模式没有附带全局匹配修饰符g,那么match()方法只能执行一次匹配。例如,下面的匹配模式中没有g修饰符,只能够执行一次匹配,返回仅有一个元素h的数组。
var a=s.match(/h/); //返回数组[h]
(2)如果没有找到匹配字符,则返回null,而不是空数组。
(3)当不执行全局匹配(即附带有g修饰符)时,如果在匹配模式中包含有子表达式,则返回的数组中存放着找到的匹配文本相关的信息。
【示例8】下面的代码使用了match()方法匹配URL字符串中所有点号字符。
var s="http://www.mysite.cn/index.html"; //匹配字符串 var a=s.match(/(\.).*(\.).*(\.)/); //执行一次匹配检索 alert(a.length); //返回4,说明返回的是一个包含4个元素的数组 alert(a[0]); //返回字符串".mysite.cn/index." alert(a[1]); //返回第一个字符.(点号),由第一个子表达式匹配并存储 alert(a[2]); //返回第二个字符.(点号),由第二个子表达式匹配并存储 alert(a[3]); //返回第三个字符.(点号),由第三个子表达式匹配并存储
在这个正则表达式“/(\.).*(\.).*(\.)/”中,左右两个斜杠是匹配模式分隔符,JavaScript解释器能够根据这两个分隔符来识别正则表达式。在正则表达式中小括号表示子表达式,每个子表达式匹配的文本信息多会被独立存储,以备调用。反斜杠表示转义序列,因为点号在正则表达式中表示匹配任意字符,星号表示前面的匹配字符可以匹配任意多次。
在上面示例中,数组a并非仅有一个元素,而包含4个元素,且每个元素存储着不同的信息。其中第一个元素存放的是匹配文本,其余的元素存放的是与正则表达式的子表达式匹配的文本。
另外,这个数组还包含两个对象属性,其中index属性存储匹配文本的起始字符在字符串中的位置,input属性存储对匹配字符串的引用。
alert(a.index); //返回值10,说明第一个点号字符的起始下标位置 alert(a.input); //返回被匹配字符串"http://www.mysite.cn/index.html"
(4)在全局匹配模式下,即附带有g修饰符。match()将执行全局匹配。此时返回的数组的内容与非全局匹配完全相同,它的数组元素存放的是字符串中所有匹配子串,该数组没有index属性和input属性。同时不再提供子表达式匹配的文本信息,也不声明每个匹配子串的位置。如果需要这些全局检索的信息,可以使用RegExp.exec()方法。
7.2.4 案例:截取子字符串
在字符串操作中,截取子字符串与查找子字符串一样都很重要。如果说查找是定位,那么截取才是操作的核心。JavaScript提供了3个字符串截取方法,如表7-2所示。
表7-2 String对象的截取子字符串方法
1.根据长度截取子字符串
substr()方法能够根据指定长度来截取子字符串。它可以包含两个参数,第一个参数表示准备截取的子串的起始下标,第二个参数表示截取的长度。
【示例1】在本示例中使用lastIndexOf()获取字符串的最后一个点号的下标位置,然后从其后的位置开始截取4个字符:
var s = "http://www.mysite.cn/index.html"; var b=s.substr(s.lastIndexOf(".")+1,4); //截取最后一个点号后4个字符 alert(b); //返回子字符串"html"
提示:使用substr()方法时,需要注意两个问题。
(1)如果省略第二个参数,则表示截取从起始位置开始到结尾的所有字符。考虑到扩展名的长度不固定,省略第二个参数会更灵活:
var b = s.substr( s.lastIndexOf( "." )+1 );
(2)如果第一个参数为负值,则表示从字符串的尾部开始计算下标位置,即-1表示最后一个字符,-2表示倒数第二个字符,依此类推。这对于左侧字符长度不固定时非常有用。
ECMAScript没有标准化该方法,所以被列为不建议选用的方法,建议使用slice()和substring()方法。
2.根据起止下标截取子字符串
slice()和substring()方法都是根据指定的起止下标位置来截取子字符串,也就是说,它们都可以包含两个参数,第一个参数表示起始下标,第二个参数表示结束下标。不过slice()方法显得更加灵活。
【示例2】下面的代码使用了substring()方法截取URL字符串中网站主机名信息。
var s = "http://www.mysite.cn/index.html"; var a=s.indexOf("www"); //获取起始点下标 var b=s.indexOf("/", a); //获取结束点下标 var c=s.substring(a, b); //返回字符串www.mysite.cn,使用substring()方法 var d=s.slice(a, b); //返回字符串www.mysite.cn,使用slice()方法
提示:使用时请注意两个问题。
(1)截取子字符串包含第一个参数所指定的字符。结束点不被截取,即不包含在子字符串中。
(2)第二个参数如果省略,表示截取到结尾的所有字符串。
但是slice()和substring()方法也存在很多不同点,具体比较如下:
区别一,如果第一个参数值比第二个参数值大,substring()方法能够在执行截取之前,先交换两个参数,而对于slice()方法来说则被视为无效,并返回空字符串。
【示例3】下面的代码比较了substring()方法和slice()方法其用法的不同。
var s = "http://www.mysite.cn/index.html"; var a=s.indexOf("www"); //获取起始点下标 var b=s.indexOf("/", a); //获取结束点下标 var c=s.substring(b, a); //返回字符串www.mysite.cn var d=s.slice(b, a); //返回空字符串
这对于起始点和结束点的值无法确定时是有效的,因为substring()方法能够自动对参数进行调整。
区别二,如果参数值为负值,则slice()方法能够把负号解释为从右侧开始定位,这与Array的slice()方法相同。但是substring()方法会视其为无效,并返回空字符串。
【示例4】下面的代码进一步比较了substring()方法和slice()方法用法的不同。
var s = "http://www.mysite.cn/index.html"; var a=s.indexOf("www"); //获取起始点下标 var b=s.indexOf("/", a); //获取结束点下标 var c=s.substring(-b, -a); //返回空字符串 var d=s.slice(-b, -a); //返回子字符串mysite.cn
7.2.5 案例:编辑字符串
字符串编辑操作主要包括替换子字符串和字符串大小写转换,具体方法如表7-3所示。
表7-3 String对象的编辑字符串方法
1.替换子字符串
replace()方法包含两个参数,第一个参数表示执行匹配的正则表达式,第二个参数表示准备代替匹配的子字符串。
【示例1】下面的代码使用了replace()方法将字符串中的“html”修改为“htm”。
var s = "http://www.mysite.cn/index.html"; var b=s.replace(/html/, "htm"); //把字符串html替换为htm alert(b); //返回字符串"http://www.mysite.cn/index.htm"
该方法第一个参数是一个正则表达式对象,也可以传递字符串,如下所示:
var b=s.replace("html", "htm"); //把字符串html替换为htm
不过replace()方法不会把字符串转换为正则表达式对象,这与查找字符串中search()和match()等几个方法不同,而是以字符串直接量的文本模式进行匹配。第二个参数可以是替换的文本,或者是生成替换文本的函数,把函数返回值作为替换文本来替换匹配文本。
【示例2】下面的代码在使用replace()方法时,灵活使用了替换函数修改匹配字符串。
var s = "http://www.mysite.cn/index.html"; function f(x){ //替换文本函数 return x.substring( x.lastIndexOf(".")+1, x.length -1 ) //获取扩展名部分字符串 } var b=s.replace(/(html)/, f(s)); //调用函数指定替换文本操作 alert(b); //返回字符串"http://www.mysite.cn/index.htm"
replace()方法实际上执行的是同时查找和替换两个操作。它将在字符串中查找与正则表达式相匹配的子字符串,然后调用第二个参数值或替换函数替换这些子字符串。如果正则表达式具有全局性质g,那么将替换所有的匹配子字符串,否则,它只替换第一个匹配子字符串。
【示例3】在replace()方法中约定了一个特殊的字符($),这个美元符号如果附加一个序号就表示对正则表达式中匹配的子表达式存储的字符串引用。
var s = "javascript"; var b=s.replace(/(java)(script)/, "$2-$1"); //交换位置 alert(b); //返回字符串"script-java"
在上面示例中,正则表达式/(java)(script)/中包含两对小括号,按顺序排列,其中第一对小括号表示第一个子表达式,第二对小括号表示第二个子表达式,在replace()方法的参数中可以分别使用字符串"$1"和"$2"来表示对它们匹配文本的引用,当然它们不是标识符,仅是一个标记,所以不可以作为变量参与计算。
除了上面约定之后,美元符号与其他特殊字符组合还可以包含更多的语义,详细说明如表7-4所示。
表7-4 replace()方法第二个参数中的特殊字符
【示例4】重复字符串。
var s = "javascript"; var b = s.replace( /.*/, "$&$&"); //返回字符串"javascriptjavascript"
由于字符串“$&”在replace()方法中被约定为正则表达式所匹配的文本,所以利用它可以重复引用匹配的文本,从而实现字符串重复显示效果。其中正则表达式“/.*/”表示完全匹配字符串。
【示例5】对匹配文本左侧的文本完全引用。
var s = "javascript"; var b = s.replace( /script/, "$& ! = $`"); //返回字符串"javascript ! = java"
其中字符“$&”代表匹配子字符串“script”,字符“$`”代表匹配文本左侧文本“java”。
【示例6】对匹配文本右侧的文本完全引用。
var s = "javascript"; var b = s.replace( /java/, "$&$' is "); //返回字符串"javascript is script"
其中字符“$&”代表匹配子字符串“java”,字符“$'”代表匹配文本右侧文本“script”。然后把"$&$' is "所代表的字符串"javascript is "替换原字符串中的"java"子字符串,即组成一个新的字符串"javascript is script"。
切换技能键与单引号键比较相似,使用时很容易混淆。
2.字符串大小写转换
String对象为了实现字符串大小写转换操作,特地定义了4个方法,其中toUpperCase()方法可以把字符串转换为大写形式,而toLowerCase()方法可以把字符串转换为小写形式。
【示例7】下面的代码将字符串全部转换为大写形式。
var s = "javascript"; alert(s.toUpperCase()); //返回字符串"JAVASCRIPT"
为了适应本地化设计需要,String对象定义了toLocaleLowerCase()和toLocaleUpperCase()两个本地化方法。它们能够按照本地方式转换大小写字母,由于只有几种语言(如土耳其语)具有地方特有的大小写映射,所以通常与toLowerCase()和toUpperCase()方法的返回值一样。
7.2.6 案例:灵活使用replace()方法
ECMAScript 3.0版本中明确规定,replace()方法的第二个参数建议使用函数,而不是字符串,JavaScipt 1.2版本和JScript 5.5版本实现了对这个特性的支持。这样当replace()方法执行匹配时,每次匹配时都会调用该函数,函数的返回值将作为替换文本执行匹配操作,同时函数可以接收以$为前缀的特殊字符组合,用来对匹配文本的相关信息的引用。
【示例1】下面的代码是使用替换函数将字符串中每个单词转换为首字母大写形式显示。
var s = 'script language = "javascript" type= " text / javascript"'; //定义字符串 var f = function($1){ //定义替换文本函数,参数为第一个子表达式匹配文本 return $1.substring( 0, 1 ).toUpperCase() + $1.substring( 1 ); //把匹配文本的首字母转换为大写 } var a=s.replace(/(\b\w+\b)/g, f); //匹配文本并进行替换 alert( a ); //返回字符串Script Language = "Javascript" Type = " Text /Javascript"
上面示例中,函数f()的参数为特殊字符“$1”,它表示正则表达式/(\b\w+\b)/中小括号每次匹配的文本。然后在函数结构内对这个匹配文本进行处理,截取其首字母并转换为大写形式,然后返回新处理的字符串。replace()方法能够在原文本中使用这个返回的新字符串替换掉每次匹配的子字符串。
【示例2】对于示例1,还可以进一步延伸,使用小括号以获取更多匹配文本的信息。例如,直接利用小括号传递单词的首字母,然后进行大小写转换处理:
var s = 'script language = "javascript" type= " text / javascript"'; var f=function($1, $2, $3){ //定义替换文本函数,请注意参数的变化 return $2.toUpperCase()+$3 ; } var a = s.replace( /\b(\w)(\w*)\b/g, f ); //返回字符串Script Language = "Javascript" Type = " Text /Javascript"
在函数f()中,第一个参数表示每次匹配的文本,第二个参数表示第一个小括号的子表达式所匹配的文本,即单词的首字母,第二个参数表示第二个小括号的子表达式所匹配的文本。
实际上,replace()方法的第二个参数是一个函数,replace()方法依然会给它传递多个实参,这些实参都包含一定的意思,具体说明如下。
第一个参数表示匹配模式相匹配的文本,如上面示例中每次匹配的单词字符串。
其后的参数是匹配模式中子表达式相匹配的字符串,参数个数不限,根据子表达式个数而定。
后面的参数是一个整数,表示匹配文本在字符串中的下标位置。
最后一个参数表示字符串自身。
【示例3】把示例2中替换文本函数改为如下形式:
var f = function(){ return arguments[1].toUpperCase()+arguments[2] ; }
也就是说,如果不为函数传递形参,直接调用函数的arguments属性,同样能够读取到正则表达式中相关匹配文本的信息。其中:
arguments[0]表示每次匹配的单词。
arguments[1]表示第一个子表达式匹配的文本,即单词的首个字母。
arguments[2]表示第二个子表达式匹配的文本,即单词的余下字母。
arguments[3]表示匹配文本的下标位置,如第一个匹配单词“script”的下标位置就是0,依此类推。
arguments[4]表示要执行匹配的字符串,这里表示“script language = "javascript" type= " text /javascript"”。
【示例4】下面的代码利用了函数的arguments对象主动获取replace()方法第一个参数中正则表达式所匹配的详细信息。
var s = 'script language = "javascript" type= " text / javascript"'; var f = function(){ for( var i = 0; i < arguments.length; i ++ ){ alert( "第" + ( i + 1 ) + "个参数的值:" + arguments[i] ); } } var a = s.replace( /\b(\w)(\w*)\b/g, f );
在函数结构体中,使用for循环结构遍历argumnets属性时,则发现每次匹配单词时,都会弹出5次提示信息,分别显示上面所列的匹配文本信息。其中,arguments[1]、arguments[2]会根据每次匹配文本不同,分别显示当前匹配文本中子表达式匹配的信息,arguments[3]显示当前匹配单词的下标位置。而arguments[0]总是显示每次匹配的单词,arguments[4]总是显示被操作的字符串。
【示例5】下面代码能够自动提取字符串中的分数,并汇总、算出平均分。然后利用replace()方法提取每个分值,与平均分进行比较以决定替换文本的具体信息。
var s="张三56分,李四74分,王五92分,赵六84分"; //定义字符串直接量 var a=s.match(/\d+/g), sum=0; //匹配出所有分值,输出为数组 for(var i=0; i<a.length; i++){ //遍历数组,求总分 sum+=parseFloat(a[i]); //把元素值转换为数值后递加 }; var avg=sum/a.length; //求平均分 function f(){ var n = parseFloat(arguments[1]); //把匹配的分数转换为数值,第一个子表达式 return n + "分" + " ( " + (( n > avg ) ? ( "超出平均分" + ( n - avg ) ) : ("低于平均分"+(avg-n)))+"分 )"; //设计替换文本的内容 } var s1=s.replace(/(\d+)分/g, f); //执行匹配、替换操作 alert( s1 ); //返回字符串“张三56分(低于平均分20.5分),李四74分(低于平均分2.5分),王五92分( 超出平均分15.5分 ),赵六84分 ( 超出平均分7.5分)”
在上面的示例中,应注意两个细节。
(1)遍历数组时不能够使用for/in结构,因为在这个数组中还存储有其他相关的匹配文本信息。应该使用for结构来实现。
(2)由于截取的数字都是字符串类型,应该把它们都转换为数值类型,否则会被误解,如把数字连接在一起,或者按字母顺序进行比较等。
7.2.7 案例:比较字符串
JavaScript在比较字符串大小时,严格按着逐字符进行比较,比较的标准是根据字符的Unicode编码大小来定。
【示例1】小写字母a的编码为97,大写字母A的编码为65,则比较时字符串"a"就大于"A"。
alert("a">"A"); //返回true
用户也可以根据本地的一些约定来进行排序。例如,在西班牙语中根据本地排序约定,“ch”将作为一个字符排在“c”和“d”之间。为此,String对象定义了localeCompare()方法,它能够根据本地特定的顺序来比较两个字符串。ECMAScript标准没有规定如何进行本地特定的比较操作,它只规定该函数采用底层(即操作系统)提供的排序规则进行操作。
【示例2】下面的代码将字符串"javascript"转换为数组,然后按本地字符顺序进行排序。
var s="javascript"; //定义字符串直接量 var a=s.split(""); //把字符串转换为数组 var s1=a.sort(function(a, b){ //对数组进行排序 return a.localeCompare(b) //将根据前后字符在本地的约定进行排序 }); a=s1.join(""); //然后再把数组还原为字符串 alert(a); //返回字符串"aacijprstv"
如果为localeCompare()方法指定的字符小于参数字符,则localeCompare()返回小于0的数,如果为该方法指定的字符大于参数字符,则返回大于0的数,如果两个字符串相等,或根据本地排序规约没有区别,该方法返回0。对于一般计算机系统来说,默认排序约定都是按着字符编码来执行。
7.2.8 案例:把字符串转换为数组
String对象的join()方法能够把数组元素连接为字符串。而要把字符串分隔为数组,可以使用String对象的split()方法。它能够根据指定的分隔符把字符串劈为数组,数组中不包含分隔符。
【示例1】如果参数为空字符串,则split()方法能够按单个字符进行分切,然后返回与字符串等长的数组。
var s = "javascript"; var a=s.split(""); //按字符空隙分割 alert(s.length); //返回值为10 alert(a.length); //返回值为10
【示例2】如果参数为空,则split()方法能够把整个字符串作为一个元素的数组返回,它相当于把字符串转换为数组。
var s = "javascript"; var a=s.split(); //空分割 alert(a.constructor==Array); //返回true,说明是Array实例 alert(a.length); //返回值为1,说明没有对字符串进行分割
【示例3】如果参数为正则表达式,则split()方法能够以匹配文本作为分隔符进行切分。
var s = "a2b3c4d5e678f12g"; var a=s.split(/\d+/); //把匹配的数字作为分隔符来切分字符串 alert(a); //返回数组[a, b, c, d, e, f, g] alert(a.length); //返回数组长度为7
【示例4】如果正则表达式匹配的文本位于字符串的边沿,则split()方法也执行分切操作,且为数组添加一个空元素。但是在IE浏览器中会忽略边沿空的字符串,而不是把它作为一个空元素来看待。
var s="122a2b3c4d5e678f12g"; //虽然字符串左侧也有匹配的数字 var a=s.split(/\d+/); //把匹配的数字作为分隔符来切分字符串 alert(a); //返回数组[, a, b, c, d, e, f, g] alert(a.length); //返回数组长度为8
如果在字符串中指定的分隔符没有找到,则返回一个包含整个字符串的数组。
【示例5】split()方法支持第二个参数,该参数是一个可选的整数,用来指定返回数组的最大长度。如果设置了该参数,返回的数组长度不会多于这个参数指定的值。如果没有设置该参数,整个字符串都被分割,不考虑数组长度。
var s = "javascript"; var a=s.split("",4); //按顺序从左到右,仅分切4个元素的数组 alert(a); //返回数组[j, a, v, a] alert(a.length); //返回值为4
【示例6】如果想使返回的数组包括分隔符或分隔符的一个或多个部分,可以使用带子表达式的正则表达式来实现。
var s = "aa2bb3cc4dd5e678f12g"; var a=s.split(/(\d)/); //使用小括号包含数字分隔符 alert(a); //返回数组[aa,2, bb,3, cc,4, dd,5, e,6, ,7, ,8, f,1, ,2, g]
但是IE浏览器对其支持得不是很好,使用时应慎重。
7.2.9 案例:字符串的类型和值
String对象支持toString()方法,该方法能够返回字符串的原始字符串值。
【示例1】下面的示例是使用toString()方法读取字符串"javascript"的字符表示。
var s = "javascript"; var a=s.toString(); //返回字符串"javascript"
由于该方法的返回值与字符串本身相同,所以一般不会调用这个方法。
【示例2】valueOf()方法与toString()方法功能相同,它也能够返回字符串的原始值。
var s = "javascript"; var a=s.valueOf(); //返回字符串"javascript"
【示例3】在JavaScript中,任何对象都支持toString()方法。不过,用户可以重写该方法,实现更个性的显示。
var s = "abcdef"; document.writeln(s); //显示字符串"abcdef" document.writeln(s.toString()); //调用字符串的方法toString(),把字符串对象转换为字符串显示 //重写String对象的原型方法toString() //参数color表示显示字符串的颜色 String.prototype.toString = function(color){ var color=color||"red"; //如果省略参数,则显示为红色 return '<font color="' + color + '">' + this.valueOf() + '</font>'; //返回格式化显示带有颜色的字符串 } document.writeln(s.toString()); //显示红色字符串"abcdef" document.writeln(s.toString("blue")); //显示蓝色字符串"abcdef"
上面的示例通过重写String对象的原型方法toString(),从而能够在不同字符串中调用toString()方法时,可以以彩色效果显示字符串的值。
7.2.10 案例:格式化字符串
为了适应浏览器的字符串显示需要,JavaScript还定义了一组格式化字符串的方法,如表7-5所示,这些方法比较奇怪、偏僻,也很少有人听过,主要是因为它们与HTML标签功能发生了重叠。注意,由于这些方法没有获得ECMAScript标准的支持,所以不建议读者大范围使用。
表7-5 String对象的格式化字符串方法
【示例】本示例演示了如何使用上面字符串方法为字符串定义格式化显示属性:
var s = "abcdef"; document.write(s.bold()); //定义加粗显示字符串"abcdef" document.write(s.link("http://www.mysite.cn/")); //为字符串"abcdef"定义超链接,指向mysite.cn域名 document.write(s.italics()); //定义斜体显示字符串"abcdef" document.write(s.fontcolor("red")); //定义字符串"abcdef"红色显示
上面的方法要受浏览器对应标签或属性支持影响,如IE不支持blink标签,那么字符串调用blink()之后,在IE下是无效的。