本文从一道简单的字符串面试题开始,记录字符串的一些方法,关注细节。
最近遇到一道面试题,觉得挺有意思,虽然简单缺发人深省。题目大致如下:写一个字符串转成驼峰的方法,例.bottom.color->borderBottomColor。
操作字符串数组#
大部分人应该都能写出这种方法,对字符串进行处理然后拼接成新的字符串。主要考察字符串的几个 API,使用 charAt (n) 来取得字符串第 n 个下标的字符,也可以使用数组下标 ([]) 来取。
function tranformStr(str) {
var strArr = str.split(".");
for (var i = 1; i < strArr.length; i++) {
strArr[i] = strArr[i].charAt(0).toUpperCase() + strArr[i].substring(1);
}
return strArr.join("");
}
正则表达式#
第二种使用正则来解决,其实算是字符串的 replace 方法和正则的结合,难点主要还是在于 replace 方法的掌握。
function transformStr(str) {
var re = /\.(\w)/g;
return str.replace(re, function(match, p1) {
return p1.toUpperCase();
});
}
从以上两种方法可以看出,使用正则的代码量更少,但是对正则的理解和 replace 用法的要求也更高,下面总结一下 replace 这个字符串方法的一些 api。
replace 使用#
str.replace(regexp|substr, newSubStr|function)
replace 方法的第一个参数可以是一个正则或者字符串。
- regexp (pattern)
一个正则表达式(RegExp) 对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉。
- substr (pattern)
一个要被 newSubStr 替换的字符串。其被视为一整个字符串,而不是一个正则表达式。仅仅是第一个匹配会被替换。
replace 方法的第二个参数可以是一个字符串或者函数。
- newSubStr (replacement)
用于替换掉第一个参数在原字符串中的匹配部分的字符串。该字符串中可以内插一些特殊的变量名。参考下面的使用字符串作为参数。
- function (replacement)
一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。参考下面的指定一个函数作为参数。
replace 方法并不改变调用它的字符串本身,而只是返回一个新的替换后的字符串。
在进行全局的搜索替换时,正则表达式需包含 g 标志。
使用字符串作为参数#
当第二个参数是字符串时,替换字符串可以插入下面的特殊变量名:
变量名 | 代表的值 |
---|---|
$$ | 插入一个 "$"。 |
$& | 插入匹配的子串。 |
$` | 插入当前匹配的子串左边的内容。 |
$' | 插入当前匹配的子串右边的内容。 |
$n | 假如第一个参数是 RegExp 对象,并且 n 是个小于 100 的非负整数,那么插入第 n 个括号匹配的字符串。 |
下面是特殊变量名的具体使用:
"border.bottom.color".replace(/\.(\w)/g, "$$");
// border$ottom$olor
"border.bottom.color".replace(/\.(\w)/g, "$&");
// border.bottom.color
"border.bottom.color".replace(/\.(\w)/g, "$`");
// borderborderottomborder.bottomolor
"border.bottom.color".replace(/\.(\w)/g, "$1");
// borderbottomcolor
指定一个函数作为参数#
当第二个参数是一个函数时,在这种情况下,当匹配执行后, 该函数就会执行。 函数的返回值作为替换字符串。 (注意:上面提到的特殊替换参数在这里不能被使用。) 另外要注意的是, 如果第一个参数是正则表达式, 并且其为全局匹配模式, 那么这个方法将被多次调用, 每次匹配都会被调用。
变量名 | 代表的值 |
---|---|
match | 匹配的子串。(对应于上述的 $&。) |
p1,p2, ... | 假如 replace () 方法的第一个参数是一个 RegExp 对象,则代表第 n 个括号匹配的字符串。(对应于上述的 $1,$2 等。) |
offset | 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 “abcd”,匹配到的子字符串是 “bc”,那么这个参数将是 1) |
string | 被匹配的原字符串。 |
注意:精确的参数个数依赖于 replace () 的第一个参数是否是一个正则表达式对象, 以及这个正则表达式中指定了多少个括号子串。
在文章最开始的题目中,我们需要匹配。后面跟着的第一个字母,并且将其替换为大写字母。具体实现代码如下:
function transformStr(str) {
var re = /\.(\w)/g;
return str.replace(re, function(match, p1) {
return p1.toUpperCase();
});
}
首先,声明一个正则 re,匹配一个。后面跟着一个括号,这个括号称为捕获括号,匹配的内容会被记住以供第二个参数使用,捕获括号内的 \w 匹配一个单字字符(字母、数字或者下划线),等价于 [A-Za-z0-9]。第二个参数为函数,第一个字符串 match 是每次匹配到的字符串,在上述例子中就是.b 和.c,p1 则对应第一个括号匹配的字符串,对应 b 和 c,在函数内部对 p1 进行大写转换,因为 replace 产生的是一个全新的字符串,所以需要 return 出去。