输入字符串'a(3)b(1)cde(2)f(0)',得到输出结果:'aaabcdee'。
其中括弧内的数字是括弧前面字母的重复次数;如果字母后面没有括弧,就原样输出(相当于重复1次);括弧内数字为0则不输出。
这道题其实非常简单,但是有多种解题思路,涉及的基本知识点也很多。下面我会按照我觉得由低到高的方式一一列举出来。
第一步当然是把字符串放到变量 str
里面,下文我们都会用这个变量:
let str = 'a(3)b(1)cde(2)f(0)';
1. 最基本的方法
最基本的方法就是遍历这个字符串。
如何遍历字符串?
字符串其实是有下标的,所以可以直接用for循环:
for (let i = 0; i < str.length; i++) {
// 这里 str[i] 便可以拿到每个字符
}
抽象暂存数据
这个题目最重要的一步,是要在输出所需字符串之前,抽象出规则,暂存数据以备我们拼接成输出字符串。
这里我们把所需数据放到一个数组tempArr里面,遍历字符串时,遇到字母或数字就将其放到这个数组:
let tempArr = [];
在 tempArr
中,我们期望每一个元素的格式是这样的:
{
charactor: 'a',
repeat: 3
}
这样我们抽象出了一份数据,数据中包含了输出的字母 charactor 和需要重复的次数 repeat。
如何判断字母或数字?
这个字符串中,我们只要判断 str[i]
不等于 (
或 )
就好了,当然,为了安全,我们还是要校验字母和数字,大家一定可以想到用正则表达式,那如果不用正则呢?
校验字母就需要把26个字母和10个数字拼成字符,然后用 indexOf
来判断。
判断是不是数字,也可以用 isNaN
,在给定字符串中,isNaN(str[i]) === false
则代表 i 位是数字。
当然,为了逻辑严谨,我们还要考虑括号前的字符可能不仅仅是字母怎么办。如果括弧内不是数字还要做容方案。
使用正则判断字母和数字使用 [a-z]
和 \d
,不再赘述。
开始遍历
上面我们已经写了一个for循环,为了让代码更为“优雅”,我们也可以将字符串分割为数组,然后使用 forEach
:
str.split('').forEach((el, i) => {
// 声明一个本轮循环的变量
let temp = {};
if(/[a-z]/.test(str[i])) {
// 如果是字母
// 将字母放入抽象数据
temp.charactor = str[i];
if (str[i+1] === '(') {
// 判断字母后面的字符是什么
// 如果字母后面是左括弧,那重复次数就是该字母后2位
temp.repeat = parseInt(str[i+2]);
} else {
// 字母后面不是左括弧,那就是省掉次数的字母(或最后一位是字母),如给定字符串中的 c、d,这时候其实 repeat 就是 1
temp.repeat = 1;
}
// 把本轮抽象出来的数据push到上文已声明的数组
tempArr.push(temp);
}
// 如果不是字母(括弧或数字)不做任何处理继续往后遍历
});
通过上面的处理,我们就可以得到这样的一个数据:
[
{ charactor: 'a', repeat: 3 }
{ charactor: 'b', repeat: 1 }
{ charactor: 'c', repeat: 1 }
{ charactor: 'd', repeat: 1 }
{ charactor: 'e', repeat: 2 }
{ charactor: 'f', repeat: 0 }
]
我们只需要循环上面的数组,就可以得到需要输出的字符串了。
一些脑洞
多余的括弧
我们其实可以发现,给定字符串中的左右括弧,完全是干扰项。我们可以第一步就把这些括弧去掉,把给定字符串由 a(3)b(1)cde(2)f(0)
变为 a3b1cde2f0
,这会让给定字符串看起来更清晰,但是用处不大。
使用map()
我们抽象出一个数据结构之后,再拼装为所需要输出的字符串。这一步没有很复杂,所以我们也可以放在循环里面,然后使用 map
替换 forEach
来处理,最后通过 join()
转为输出字符串:
let newStr = str.split('').map((el, i) => {
let tempStr = '';
if(/[a-z]/.test(el)) {
if (str[i+1] === '(') {
for (let j = 0; j < parseInt(str[i+2]); j++) {
// 根据数字循环字母
tempStr += el;
}
} else {
tempStr = el;
}
}
return tempStr;
}).join('');
console.log(newStr);
2. 更妙的方法
这个题目更好的方式是用正则表达式,从一个字符串到另一个字符串,我们只需要用到字符串的 replace
方法。
这其中最关键的点,是如何用正则匹配出一组一组的数据,在给定字符串中,可以划分为:'a(3)','b(2)','c','d'……这样的几组,需要根据这些写出一个匹配的正则表达式:/(\w)\((\d)\)/
。
把正则表达式作为第一个参数给 replace
,第二个参数使用一个处理函数返回需要的内容即可。这样我们只需要1行代码来解决这个问题,大家可以体会下:
'a(3)b(1)cde(2)f(0)'.replace(/(\w)\((\d)\)/g, (match, $1, $2) => Array(+$2).fill($1).join(''));
这一行中包括了:正则 replace、数组长度、字符串转数字、fill()、join() 等知识点。
您的赞助将会支持作者创作及本站运维
发表评论