简体   繁体   中英

count the number of occurrences of items in a list that appear in a string in javascript

I want to be able to specify a list of characters/strings and find out how many occurrences from the list are in a given string.

const match = ['&', '|', '-', 'abc'];
const input = 'This & That | Or | THIS - Foo abc';

result should return 5 .

I can loop over the match and do indexOf with a counter, but I'm wondering if there is some easier way with reduce .

Rather than looping over the match array, you could split the input string, filter it, and then get the length.

Here is a simple one-liner:

input.split('').filter(x => match.indexOf(x) > -1).length;

Snippet:

 const match = ['&', '|', '-']; const input = 'This & That | Or | THIS - Foo'; const count = input.split('').filter(x => match.indexOf(x) > -1).length; console.log(count); // 4

You can use regexp to find the matching characters:

function escape(chr) { return '\\' + chr; }

input.match(new RegExp(match.map(escape).join('|'), "g")).length

The escaping is necessary to avoid problems with characters such as | which have special meaning in regexps.

Since you asked for reduce:

let count = Array.prototype.reduce.call(input, (counter, chr) => (counter + (match.indexOf(chr)!==-1 ? 1: 0)), 0)

UPDATED:

Based on comments on other answers, OP would like the ability to also search substrings like 'abc' in addition to individual characters. Here's a more elegant solution which you can put in a local module.

There are 2 functions that work together: one escapes the special characters in match, the other does the counting. And using reduce again...

 // This escapes characters const escapeRegExp = (str) => ( str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, "\\\\$&") ) // This returns the count const countMatches = (input, match, i = true) => ( match.reduce((c, pattern) => ( c + input.match(new RegExp(escapeRegExp(pattern), (i ? 'ig' : 'g'))).length ), 0) ) // OP's test case let match = ['&', '|', '-'], input = 'This & That | Or | THIS - Foo', count = countMatches(input, match) console.log('Expects 4: ', count, 4 === count) // Case Sensitive Test match = ['abc'] input = 'This ABC & That abc | Or | THIS - Foo' count = countMatches(input, match, false) console.log('Expects 1: ', count, 1 === count) // Case Insensitive Test count = countMatches(input, match) console.log('Expects 2: ', count, 2 === count)

You can use .map() , .filter() , with .reduce() chained to add element of resulting array

 const match = ['&', '|', '-']; const input = 'This, & That | Or | THIS - Foo'; let res = match .map(v => [...input].filter(c => c === v).length) .reduce((a, b) => a + b) console.log(res);

You can also use for..of loop to iterate each character, String.prototype.contains() , if supported, or .some() , to check if character is within joined string match .

 let n = 0;
 let m = match.join("");
 for (let str of input) m.contains(str) && (n += 1);

for (let str of input) match.some(s => s === str) && (n += 1);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM