计算带或不带string.slice的字符串中的字符

时间:2019-04-28 17:57:19

标签: javascript

我正在尝试学习如何解决此问题,但此后我迷路于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;
}

6 个答案:

答案 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; 
  }

谢谢