yqbk
yqbk

Reputation: 726

Counting occurrences of a word in a string with Javascript using match

I am trying to count occurrences of each word in longer text using the match method, but instead of result I get only an error:

Cannot read property 'length' of null

My function looks like this:

const myText = "cat dog stop rain cat"

myText.split(" ").forEach((word) => {
  const numberOfOccurrences = myText.match(/word/g).length
  console.log(`${word} - ${numberOfOccurrences}`)
})

How can I repair it to get the proper result?

Upvotes: 1

Views: 11455

Answers (6)

Nischith
Nischith

Reputation: 166

I agree with above answer but if in case you looking with array of strings this will do

var textArr = ['apple', 'mango' ,'apple', 'apple' ,'cherry'];
var arr = [...new Set(textArr)];

arr.forEach(v => console.log(`${v} appears: ${textArr.filter(c => c == v).length} times`));

Upvotes: 0

Andrew Li
Andrew Li

Reputation: 57944

The regular expression is literally matching word, as variable word is never indicated. There is no match found in the string myText so it's null, hence the error. Try like this:

myText.match(new RegExp(word, "g")).length

This uses the RegExp constructor, which takes in two arguments: the pattern and the flags. The above will pass the actual value of word instead of the literal word, and the flag g. It's equivalent to /word/g except word is correctly matched to what word is passed. See the following snippet:

const myText = "cat dog stop rain cat"

myText.split(" ").forEach((word) => {
  const numberOfOccurrences = myText.match(new RegExp(word, "g")).length
  console.log(`${word} - ${numberOfOccurrences}`)
})

As others have pointed out, there are better ways to do this. The output of your code above outputs the occurrence of cat twice, because it occurs twice. I would recommend saving your counts in an object and updating the counts at each pass, which ibrahim mahrir shows in their answer. The idea is to use reduce to iterate over the split array, and reduce with the initial value of an empty object. Then, the empty object is updated with the counts of the word added by one, with initial count of zero.

Upvotes: 8

Daniel Smith
Daniel Smith

Reputation: 1034

I think your example is just trying to match the literal word. You should use RegExp(word, "gi" instead.

const myText = "cat dog stop rain cat"

myText.split(" ").forEach((word) => {
  const numberOfOccurrences = myText.match(RegExp(word, "gi")).length
  console.log(`${word} - ${numberOfOccurrences}`)
})

Upvotes: 0

Simon Hyll
Simon Hyll

Reputation: 3608

Your expression returns an array, which has one entry, hence it always returns 1. You also have to create a regexp from the word because match takes a regexp and not a string as its argument.

Try this instead

const myText = "cat dog stop word rain cat"

myText.split(" ").forEach((word) => {
  const numberOfOccurrences = myText.match(new RegExp(word, 'g')).length;
  console.log(`${word} - ${numberOfOccurrences}`)
})

Upvotes: 0

kind user
kind user

Reputation: 41893

You can also try simple solution with Array#filter, without using RegExp and Array#match.

var text = "cat dog stop rain cat";
var textArr = text.split(' ');
var arr = [...new Set(text.split(' '))];

arr.forEach(v => console.log(`${v} appears: ${textArr.filter(c => c == v).length} times`));

Upvotes: 1

ibrahim mahrir
ibrahim mahrir

Reputation: 31682

It's because nothing is matched. There is no word word in your string. Try this:

const myText = "cat dog stop rain cat"

myText.split(" ").forEach((word) => {
  const numberOfOccurrences = myText.match(new RegExp(word, 'g')).length;
  console.log(`${word} - ${numberOfOccurrences}`)
})

Without regular expressions:

Use a hash object like this:

const myText = "cat dog stop rain cat"

var result = myText.split(" ").reduce((hash, word) => {
  hash[word] = hash[word] || 0;
  hash[word]++;
  return hash;
}, {});

console.log(result);

Upvotes: 0

Related Questions