计算Javascript中字符串中出现的字符数

467 javascript string

我需要计算一个字符串中出现的字符数.

例如,假设我的字符串包含:

var mainStr = "str1,str2,str3,str4";
Run Code Online (Sandbox Code Playgroud)

我想找到逗号,字符的计数,即3.以逗号分割后的单个字符串的计数,即4.

我还需要验证每个字符串,即str1或str2或str3或str4不应超过15个字符.

Bjo*_*orn 683

我已经更新了这个答案.我更喜欢使用匹配的想法,但速度较慢:

console.log(("str1,str2,str3,str4".match(/,/g) || []).length); //logs 3

console.log(("str1,str2,str3,str4".match(new RegExp("str", "g")) || []).length); //logs 4
Run Code Online (Sandbox Code Playgroud)

的jsfiddle

如果您事先知道要搜索的内容,请使用正则表达式文字,否则可以使用RegExp构造函数,并将该g标志作为参数传入.

match返回null没有结果因此|| []

我在2009年做出的原始答案如下.它不必要地创建一个数组,但使用拆分更快(截至2014年9月).我很矛盾,如果我真的需要速度,毫无疑问我会使用分裂,但我宁愿使用匹配.

旧答案(2009年起):

如果您正在寻找逗号:

(mainStr.split(",").length - 1) //3
Run Code Online (Sandbox Code Playgroud)

如果你正在寻找str

(mainStr.split("str").length - 1) //4
Run Code Online (Sandbox Code Playgroud)

@Lo的答案和我自己的愚蠢的jsperf测试中,两者都在速度方面领先,至少在Chrome中,但再次创建额外阵列似乎并不健全.

  • 我真的不喜欢使用正则表达式,因为"你更喜欢它".正则表达式有其目的,但通常当有一个简单的非正则表达式解决方案时,它是一个更好的选择.另请注意,两种方法都会创建一个数组,因此这也不是使用正则表达式的理由. (49认同)
  • split()是javascript中的基本工具,概念上很简单,并且对splits进行计数给出了明确的意图并且完全可读. (25认同)
  • 测试显示Firefox在拆分时比任何其他浏览器快得多.http://jsperf.com/count-the-number-of-occurances-in-string (7认同)
  • 呃,我刚刚测试了vsync的jsperf,正则表达式在Chrome,Firefox和IE中都比较慢*.分别为68%,100%和14%.我有一台i7 2600. (3认同)
  • 我喜欢它*在这种情况下*是有原因的.将字符串拆分为数组以获得多次出现是一种获取该信息的方法.拆分数组只是因为实现细节更快,可以改变,而获得匹配数是可读性的改进,意图是显而易见的,不会创建和填充未使用的数据结构. (3认同)
  • 那么您是说“新”版本的长度增加了 50%,并且运行速度更慢?我会坚持*“老方法”,*谢谢! (3认同)
  • bjorn - 不幸的是,正则表达式不仅仅是一个"匹配" - 它在一个数组中返回结果,通过全局搜索,您可以获得一系列结果.因此,从"创建阵列看起来似乎不健全"的角度来看,分裂可能更好. (2认同)
  • @Abrar `^` 在正则表达式中具有特殊含义。改用`/\^/g` 来匹配文字`^` 字符。 (2认同)

Lor*_*uer 204

至少有四种方式.最佳选择,也应该是本机RegEx引擎的最快 - 位于顶部.jsperf.com目前正在关闭,否则我会为您提供性能统计数据.

更新:请在此处查找性能测试,并自行运行,以便提供性能结果.稍后将给出结果的具体细节.

1.

 ("this is foo bar".match(/o/g)||[]).length
 //>2
Run Code Online (Sandbox Code Playgroud)

2.

"this is foo bar".split("o").length-1
 //>2
Run Code Online (Sandbox Code Playgroud)

拆分不推荐.资源匮乏.为每个匹配分配"Array"的新实例.不要通过FileReader尝试> 100MB的文件.您可以使用Chrome的分析器选项轻松地观察EXACT资源使用情况.

3.

var stringsearch = "o"
   ,str = "this is foo bar";
for(var count=-1,index=-2; index != -1; count++,index=str.indexOf(stringsearch,index+1) );
 //>count:2
Run Code Online (Sandbox Code Playgroud)

4.

搜索单个字符

var stringsearch = "o"
   ,str = "this is foo bar";
for(var i=count=0; i<str.length; count+=+(stringsearch===str[i++]));
 //>count:2
Run Code Online (Sandbox Code Playgroud)

更新:

5.

元素映射和过滤,由于其整体资源预分配而不是使用Pythonian'generator'而不推荐

var str = "this is foo bar"
str.split('').map( function(e,i){ if(e === 'o') return i;} )
             .filter(Boolean)
//>[9, 10]
[9, 10].length
//>2
Run Code Online (Sandbox Code Playgroud)

分享: 我用这8个字符统计方法制作了这个要点,所以我们可以直接汇集和分享我们的想法 - 只是为了好玩,也许是一些有趣的基准:)

https://gist.github.com/2757250

  • 我花了一点时间才意识到`|| []`正在做什么,但这个答案很棒!对于任何其他人来说,如果没有找到匹配,`match()`返回`null`如果`match()`返回`null`,`|| []`将返回一个0长度数组,意思是'length( )`将返回0而不是产生类型错误. (24认同)
  • 你的第三种方法(不幸的是,也是最快的)将丢失大海捞针索引0处的任何匹配.您可以通过使用do ... while循环来修复它:var strsearch ="o",str ="othis is foo bar",index = -1,count = -1; do {index = str.indexOf(strsearch,index + 1); 计数++; } while(index!= -1); 计数 (3认同)
  • Lo Sauer,没有必要为自己辩护,代码是可靠的,我通过弄清楚它是如何工作我自己学到的东西:)我更喜欢这种方法而不是实际标记为答案的方法.如果我们不打算使用结果,则不需要拆分字符串. (2认同)

小智 19

将此函数添加到sting原型:

String.prototype.count=function(c) { 
  var result = 0, i = 0;
  for(i;i<this.length;i++)if(this[i]==c)result++;
  return result;
};
Run Code Online (Sandbox Code Playgroud)

用法:

console.log("strings".count("s")); //2
Run Code Online (Sandbox Code Playgroud)

  • @Toskan请看一下OP的问题,这是关于“一个角色”的。我想这就是为什么参数被称为“c”而不是“s” - 代表“[c]character”,而不是“[s]tring”。大多数其他答案都是可怕的,人们为这个极其简单的任务扔掉数组和额外的对象,就好像内存分配是免费的一样。 (2认同)

Joe*_*app 18

更新:这可能很简单,但不是最快的。请参阅下面的基准。


令人惊奇的是,13年来,这个答案却没有出现。直觉上,它似乎应该是最快的:

const s = "The quick brown fox jumps over the lazy dog.";
const oCount = s.length - s.replaceAll('o', '').length;
Run Code Online (Sandbox Code Playgroud)

如果字符串中只有两种字符,则速度更快:


const s = "001101001";
const oneCount = s.replaceAll('0', '').length;
Run Code Online (Sandbox Code Playgroud)

基准

const { performance } = require('node:perf_hooks');

const ITERATIONS = 10000000;
const TEST_STRING = "The quick brown fox jumps over the lazy dog.";

console.log(ITERATIONS, "iterations");

let sum = 0; // make sure compiler doesn't optimize code out
let start = performance.now();
for (let i = 0; i < ITERATIONS; ++i) {
  sum += TEST_STRING.length - TEST_STRING.replaceAll('o', '').length;
}
let end = performance.now();
console.log("  replaceAll duration", end - start, `(sum ${sum})`);

sum = 0;
start = performance.now();
for (let i = 0; i < ITERATIONS; ++i) {
  sum += TEST_STRING.split('o').length - 1
}
end = performance.now();
console.log("  split duration", end - start, `(sum ${sum})`);
Run Code Online (Sandbox Code Playgroud)
10000 iterations
  replaceAll duration 2.6167500019073486 (sum 40000)
  split duration 2.0777920186519623 (sum 40000)
100000 iterations
  replaceAll duration 17.563208997249603 (sum 400000)
  split duration 8.087624996900558 (sum 400000)
1000000 iterations
  replaceAll duration 128.71587499976158 (sum 4000000)
  split duration 64.15841698646545 (sum 4000000)
10000000 iterations
  replaceAll duration 1223.3415840268135 (sum 40000000)
  split duration 629.1629169881344 (sum 40000000)
Run Code Online (Sandbox Code Playgroud)


use*_*751 10

一个快速的谷歌搜索得到了这个(来自http://www.codecodex.com/wiki/index.php?title=Count_the_number_of_occurrences_of_a_specific_character_in_a_string#JavaScript)

String.prototype.count=function(s1) { 
    return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length;
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

test = 'one,two,three,four'
commas = test.count(',') // returns 3
Run Code Online (Sandbox Code Playgroud)

  • 现在快速谷歌搜索带我到这里:) (13认同)
  • `*`char的错误(`SyntaxError:没有重复') (4认同)

Yos*_*ero 9

您还可以休息您的字符串并像使用元素数组一样使用它

const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].filter(l => l === ',').length;

console.log(commas);
Run Code Online (Sandbox Code Playgroud)

或者

const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].reduce((a, c) => c === ',' ? ++a : a, 0);

console.log(commas);
Run Code Online (Sandbox Code Playgroud)


Pra*_*ena 8

只需使用拆分即可找出字符串中字符出现的次数。

mainStr.split(',').length //给出4,这是使用定界符逗号分割后的字符串数

mainStr.split(',').length - 1 // //给出3,这是逗号的计数


Use*_*der 6

更新06/10/2022

因此,我运行了各种性能测试,如果您的用例允许,似乎使用 split 将执行最佳的整体性能。


function countChar(char: string, string: string): number  {

  return string.split(char).length - 1

}

countChar('x', 'foo x bar x baz x')

Run Code Online (Sandbox Code Playgroud)

原答案

我知道我参加这里的聚会迟到了,但我很困惑没有人用最基本的方法回答这个问题。社区为此问题提供的大部分答案都是基于迭代的,但所有答案都是基于每个字符在字符串上移动,这并不是真正有效。

当处理包含数千个字符的大字符串时,遍历每个字符来获取出现次数可能会变得相当无关紧要,更不用说代码味道了。以下解决方案利用sliceindexOf值得信赖的传统while循环。这些方法使我们不必遍历每个字符,并将大大加快计算出现次数所需的时间。它们遵循与需要字符串遍历的解析器和词法分析器中类似的逻辑。

与切片一起使用

在这种方法中,我们正在利用slice每场indexOf比赛,我们都会在字符串中移动并消除之前搜索到的药水。每次我们调用时,indexOf它搜索的字符串的大小都会变小。

function countChar (char: string, search: string): number {
  
  let num: number = 0;
  let str: string = search;
  let pos: number = str.indexOf(char);
  
  while(pos > -1) {
    str = str.slice(pos + 1);
    pos = str.indexOf(char);
    num++;
  }

  return num;

}

// Call the function
countChar('x', 'foo x bar x baz x') // 3

Run Code Online (Sandbox Code Playgroud)

与位置上的 IndexOf 一起使用

与第一种方法类似slice,但我们不是增加正在搜索的字符串,而是利用方法from中的参数indexOf

function countChar (char: string, str: string): number {
  
  let num: number = 0;
  let pos: number = str.indexOf(char);
  
  while(pos > -1) {
    pos = str.indexOf(char, pos + 1);
    num++;
  }

  return num;

}

// Call the function
countChar('x', 'foo x bar x baz x') // 3

Run Code Online (Sandbox Code Playgroud)

就我个人而言,我倾向于第二种方法而不是第一种,但是在处理大字符串和较小尺寸的字符串时,两种方法都很好且性能良好。


小智 5

我发现在一个非常大的字符串中搜索字符的最佳方法(例如,长达1 000 000个字符)就是使用该replace()方法.

window.count_replace = function (str, schar) {
    return str.length - str.replace(RegExp(schar), '').length;
};
Run Code Online (Sandbox Code Playgroud)

您可以看到另一个JSPerf套件来测试此方法以及在字符串中查找字符的其他方法.


hal*_*bit 5

好的,另一个带有正则表达式的 - 可能不快,但比其他人更短且可读性更好,在我的情况下只是'_'为了计数

key.replace(/[^_]/g,'').length
Run Code Online (Sandbox Code Playgroud)

只需删除所有看起来不像你的字符的东西,但用字符串作为输入看起来不太好


Cli*_*son 5

Split 与 RegExp 的性能对比

var i = 0;

var split_start = new Date().getTime();
while (i < 30000) {
  "1234,453,123,324".split(",").length -1;
  i++;
}
var split_end = new Date().getTime();
var split_time = split_end - split_start;


i= 0;
var reg_start = new Date().getTime();
while (i < 30000) {
  ("1234,453,123,324".match(/,/g) || []).length;
  i++;
}
var reg_end = new Date().getTime();
var reg_time = reg_end - reg_start;

alert ('Split Execution time: ' + split_time + "\n" + 'RegExp Execution time: ' + reg_time + "\n");
Run Code Online (Sandbox Code Playgroud)


ula*_*mir 5

这是一个类似的解决方案,但它使用 Array.ptototype.reduce

function countCharacters(char, string) {
  return string.split('').reduce((acc, ch) => ch === char ? acc + 1: acc, 0)
}
Run Code Online (Sandbox Code Playgroud)

如前所述,String.prototype.split工作速度比快得多String.prototype.replace


Gen*_*wen 5

如果你使用 lodash,_.countBy方法会这样做:

_.countBy("abcda")['a'] //2
Run Code Online (Sandbox Code Playgroud)

此方法也适用于数组:

_.countBy(['ab', 'cd', 'ab'])['ab'] //2
Run Code Online (Sandbox Code Playgroud)