我需要计算字符串中某个字符出现的次数。
例如,假设我的字符串包含:
var mainStr = "str1,str2,str3,str4";
我想求出逗号的个数,也就是3个字符。以及按逗号分隔后的单个字符串的计数,也就是4。
我还需要验证每个字符串,即str1或str2或str3或str4不应该超过,比如说,15个字符。
我需要计算字符串中某个字符出现的次数。
例如,假设我的字符串包含:
var mainStr = "str1,str2,str3,str4";
我想求出逗号的个数,也就是3个字符。以及按逗号分隔后的单个字符串的计数,也就是4。
我还需要验证每个字符串,即str1或str2或str3或str4不应该超过,比如说,15个字符。
当前回答
我相信您会发现下面的解决方案非常短,非常快,能够处理非常长的字符串,能够支持多字符搜索,防错,并能够处理空字符串搜索。
function substring_count(source_str, search_str, index) {
source_str += "", search_str += "";
var count = -1, index_inc = Math.max(search_str.length, 1);
index = (+index || 0) - index_inc;
do {
++count;
index = source_str.indexOf(search_str, index + index_inc);
} while (~index);
return count;
}
使用示例:
console.log(substring_count("Lorem ipsum dollar un sit amet.", "m ")) 函数substring_count(source_str, search_str, index) { Source_str += "", search_str += ""; var count = -1, index_inc = Math.max(search_str. var)长度,1); Index = (+ Index || 0) - index_inc; {做 + +计数; Index = source_str。indexOf(search_str, index + index_inc); } while (~index); 返回计数; }
上面的代码修复了Jakub Wawszczyk的主要性能错误,即使在indexOf说没有匹配之后,代码仍然在寻找匹配,而且他的版本本身也不能工作,因为他忘记给函数输入参数。
其他回答
下面使用正则表达式测试长度。Testex确保不存在16个或更多的连续非逗号字符。如果它通过了测试,那么它将继续拆分字符串。计算逗号的数量就像计算符号减1一样简单。
var mainStr = "str1,str2,str3,str4";
var testregex = /([^,]{16,})/g;
if (testregex.test(mainStr)) {
alert("values must be separated by commas and each may not exceed 15 characters");
} else {
var strs = mainStr.split(',');
alert("mainStr contains " + strs.length + " substrings separated by commas.");
alert("mainStr contains " + (strs.length-1) + " commas.");
}
更新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')
我知道我来晚了,但我很困惑,没有人用最基本的方法来回答这个问题。社区对这个问题提供的大部分答案都是基于迭代的,但都是在每个字符的基础上移动字符串,这并不是真正有效的。
When dealing with a large string that contains thousands of characters walking over each character to get the occurance count can become rather extraneous not to mention a code-smell. The below solutions take advantage of slice, indexOf and the trusted traditional while loop. These approaches prevent us having to walk over each character and will greatly speed up the time it takes to count occurances. These follow similar logic to that you'd find in parsers and lexical analyzers that require string walks.
与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
使用IndexOf from position
类似于使用slice的第一种方法,但它不是扩大我们正在搜索的字符串,而是利用indexOf方法中的from参数。
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
就我个人而言,我倾向于第二种方法而不是第一种,但在处理大字符串和较小尺寸的字符串时,两者都很好且性能良好。
最快的方法似乎是通过索引操作符:
函数特征(str, char) } 对于(var c = 0, i = 0, len = str.length;我< len;+ + i) } if (str[i] == char) } c + +; } } return c; } console.log(charOccurances('example/path/script.js', '/'));/ / 2
或者作为原型函数:
String.prototype.charOccurances =函数(char) } 对于(var c = 0, i = 0, len = this.length;我< len;+ + i) } if (this[i] == char) } c + +; } } return c; } console.log('example/path/script.js'. charoccurances ('/'));/ / 2
更新:这可能是简单的,但它不是最快的。参见下面的基准测试。
令人惊讶的是,13年了,这个答案还没有出现。从直觉上看,它应该是最快的:
const s = "The quick brown fox jumps over the lazy dog.";
const oCount = s.length - s.replaceAll('o', '').length;
如果字符串中只有两种字符,那么这样仍然更快:
const s = "001101001";
const oneCount = s.replaceAll('0', '').length;
基准
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})`);
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)
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");