我正在尝试学习如何解决此问题,但此后我迷路于string.slice(0,1)
和i++
。
需要使用slice方法吗?
问题是:
编写一个名为countChars的函数,该函数接受两个参数:字符串和字符。此函数应返回一个数字,代表该字符在字符串中出现的次数。
function countChars(string, character) {
let count = 0;
let i = 0;
while (i < string.length) {
if (string[i] === character) {
count++;
}
string.slice(0, 1);
i++;
}
return count;
}
答案 0 :(得分:1)
没有切片
function countChars(string, character) {
let count = 0;
let i = 0;
while (i < string.length) {
if (string[i] === character) {
count++;
}
i++;
}
return count;
}
console.log(countChars('foobar', 'o'))
有切片,但没有i
。
function countChars(string, character) {
let count = 0;
while (string.length) { // check if the length is not zero
if (string[0] === character) {
count++;
}
string = string.slice(1); // take the rest of the string, beginning from index 1
}
return count;
}
console.log(countChars('foobar', 'o'))
答案 1 :(得分:1)
Nina已经使用您的代码解决了它,一个简短的选择是使用String.match
function countChars(string, character) {
const { length } = string.match(new RegExp(character, 'ig')) || [];
return length;
}
console.log(countChars('Foobar', 'o'));
答案 2 :(得分:0)
如果您愿意寻找其他解决方案,这里有一个简短的解决方案。
function count(str, char){
let count = str.split('').filter(c => {
return c.toLowerCase() === char.toLowerCase()
});
return count.length;
}
console.log(count('hello world', 'l'));
注意:上面的解决方案是case-insensitive
。
答案 3 :(得分:0)
我会这样
function countChars(string, character) {
return string.split('').filter(e => e === character).length;
}
console.log(countChars('foobar', 'o'))
但是@bambam RegEx方法可能是最有效的。
答案 4 :(得分:0)
function countChars(string, character) {
let count = 0; // set variable count to zero
let i = 0; // set variable i to zero
while (i < string.length) { // loop while i is less than lenght of string
if (string[i] === character) { // check character at position i
count++; // Increment count by one
}
string.slice(0, 1); // returns the first character in string, but return value is not used. Can be removed
i++; // increment variable i by one
}
return count; // returns count
}
console.log("Count", countChars("ABCDABC", "A"));
string.slice(0, 1)
slice方法提取字符串的一部分并将其作为新字符串返回,而无需修改原始字符串。此函数未使用返回值,因此可以删除该调用。我猜写它的人试图在循环的每次迭代中删除字符串的第一个字符。这不是解决问题的好方法,例如,因为它每次迭代创建一个字符串并浪费内存。
i++
增量运算符++对其操作数进行递增(加1)并返回一个值。有两种使用此运算符的方式:作为前递增++i
(在递增之前返回值)或后递增i++
(在递增之后返回值)。两种变体都是有用的。当单行使用时(如您的示例),这无关紧要。您也可以将其写为i = i + 1
或使用addition assignment i += 1
。
let value = 0;
console.log( 'Pre increment: before %d, result %d, after %d', value, ++value, value); // before 0, result 1, after 1
value = 0;
console.log( 'Post increment: before %d, result %d, after %d', value, value++, value); //before 0, result 0, after 1
使用while语句是创建遍历字符串的循环的一种方法,使用for语句是另一种更为紧凑的方法。
while
的示例:
let i = 0; // initialization
while ( i < string.length ) { // check contition
// ... some code ...
i += 1;
}
for
的示例:
for ( let i = 0; i < string.length; i += 1 ) {
// ... some code ...
}
for
的优点是:头中定义了初始化,条件和最终表达式。 i
变量的范围可以用let
限制为仅在for循环内定义。
您的示例,但有一个for
循环:
function countChars(string, character) {
let count = 0; // set variable count to zero
for (let i = 0; i < string.length; i += 1) {
if (string[i] === character) { // check character at position i
count++; // Increment count by one
}
}
return count; // returns count
}
console.log("Count", countChars("ABCDABC", "A"));
此解决方案存在一个错误,它与字符定义方式有关。在Javascript中,字符串的每个位置都是16位整数。它适用于大多数文本,但不适用于Unicode Basic Multilingual Plane中没有的表情符号和其他字符,因为它们是在字符串中的两个位置(代理对)定义的。
一种有效的解决方案是使用split方法,该方法将字符串对象拆分为字符串数组,并使用指定的分隔符字符串确定每次拆分的位置。 请注意,如果找不到分隔符字符串,或者输入字符串为空,则将返回一个包含一个字符串的数组。如果 one 匹配,则返回的数组将包含两个字符串。因此,拆分方法返回的值比我们想要的值大一个,但是通过减去一个值很容易解决。
function countChars(string, character) {
return string.split(character).length - 1;
}
console.log("Count", countChars("ABCDABC", ""));
虽然是“ Premature optimization is the root of all evil”,但是在编写代码时,有些事情可以用干净,优化的方式编写。例如,如果您正在写入文件,则打开文件,编写内容然后在循环内关闭文件的效率非常低:
for( i = 0; i < array.length; i + i = 1) {
fs.openFile("log.txt").write(array[i]).close();
}
首先打开文件,在循环中写入内容,然后关闭文件,这样效率更高,这并不奇怪:
fh = fs.openFile("log.txt");
for( i = 0; i < array.length; i + i = 1) {
fh.write(array[i]);
}
fh.close();
之所以这么说,是因为当我编写一个for语句时,我通常会在for语句的初始化部分中同时初始化变量和长度,因为字符串的长度不会改变(并且使用string.length属性总是比使用局部变量昂贵。
for (let i = 0, length = string.length; i < length; i += 1) {
// ... code ...
}
另一件事:string[i]
和string.charAt(i)
在循环的每次迭代中创建一个新字符串。要比较循环中的单个字符,使用string.charCodeAt(i)
比较整数而不是字符串要快得多。而且,除了string.charCodeAt(i)
之外,您还可以使用string.codePointAt(i)
使其可以安全地与表情符号等所有Unicode字符一起使用,而不仅限于BMP中的字符。
如上所述,您使用的方法不适用于Unicode。例如,如果搜索表情符号(),将不会得到正确的结果。
以下两种方法可安全地用于所有Unicode代码点。他们两个都可以处理带有多个字符的针。
function count_split(haystack, needle) {
return haystack.split(needle).length - 1;
}
此功能使用正则表达式作为指针,因为某些字符具有特殊含义,所以可以产生意外的结果。例如,如果您搜索一个点(。),它将匹配每个字符。另一方面,您可以对将匹配所有'a'和'b'字符的'[ab]'进行高级搜索。
function count_match(haystack, needle) {
const match = haystack.match(new RegExp(needle, 'g')) || [];
return match.length;
}
以下方法可与任何Unicode一起安全使用,并且指针必须为单个代码点。
function countChars(haystack, needle) {
let count = 0;
const codePoint = needle.codePointAt(0);
if (
!((needle.length === 1) || (needle.length === 2 && codePoint > 0xffff))
) {
// NOTE: Using charPointAt(0) returns the codePoint of the first character.
// Since the characters in the string is stored as 16-bit integers,
// characters outside of the Unicode BMP is stored as surrogate pairs
// in two positions. Thats why the length of the string is1 for
// a BMP codepoint and 2 for a codepoint outside of the BMP.
// codePointAt handles the decoding of the surrogate pair.
throw Error('needle should be one codepoint');
}
for (let i = 0, length = haystack.length; i < length; i += 1) {
if (haystack.codePointAt(i) === codePoint) {
count++;
}
}
return count;
}
我已经在jsperf.com上创建了测试用例,以比较上述Unicode safe函数的速度,以及我编写本文时在该线程中发布的UNSAFE函数的速度答案。
答案 5 :(得分:-1)
较短的版本:)
function count(string,char) {
return string.split('').filter(x => x === char).length;
}
谢谢