0

I am new to react and I am trying to count each character from textarea and display the character count. I have done the total character count but How do I count each character and display the number of characters? My code is follows :

import React, { useState } from "react";

function Home() {
  const [characterCount, setCharacterCount] = useState(0);

  const myFunction = (e) => {
    e.preventDefault();
    console.log("clicked");
  };
  return (
    <div>
      <form onSubmit={myFunction}>
        <h3>Please enter text</h3>
        <textarea
          onChange={(e) => setCharacterCount(e.target.value.length)}
          placeholder="start typing"
        ></textarea>
        <div>
          <button type="submit">submit</button>
        </div>
        <p>Total number of character :{characterCount}</p>
      </form>
    </div>
  );
}

export default Home;

output: user input

    abbbsewrrrrree
Total number of characters: 14

Expected: Example: if user input:

abbbsewrrrrree

a=1
b=3
s=1
e=3
w=1
r=5
Jenish MS
  • 357
  • 2
  • 13
Notation
  • 323
  • 6
  • 19
  • Does this help? [Count the number of occurrences of a character in a string in Javascript](https://stackoverflow.com/questions/881085/count-the-number-of-occurrences-of-a-character-in-a-string-in-javascript?rq=1). – sallf Nov 02 '21 at 03:00
  • it is different. I want to know how we count each character from textarea. – Notation Nov 02 '21 at 03:09

3 Answers3

2

I think you should make the input(textarea) controlled, as you would like to process the value (to count each character). React Controlled Components

function Home() {
  const [text, setText] = useState('');

  const myFunction = (e) => {
    e.preventDefault();
    console.log('clicked');
  };

  return (
    <div>
      <form onSubmit={myFunction}>
        <h3>Please enter text</h3>
        <textarea
          onChange={(e) => setText(e.target.value)}
          placeholder="start typing"
        ></textarea>
        <div>
          <button type="submit">submit</button>
        </div>
        <p>Total number of character :{text.length}</p>
      </form>
    </div>
  );
}

And for counting each character you could use useMemo and watch state text changes, like this:

function Home() {
  const [text, setText] = useState('');

  const myFunction = (e) => {
    e.preventDefault();
    console.log('clicked');
  };

  const eachCharResult = useMemo(() => {
    let result = {};
    for (let i = 0; i < text.length; i++) {
      if (result[text[i]]) result[text[i]]++;
      else result[text[i]] = 1;
    }
    return result;
  }, [text]);

  return (
    <div>
      <form onSubmit={myFunction}>
        <h3>Please enter text</h3>
        <textarea
          onChange={(e) => setText(e.target.value)}
          placeholder="start typing"
        ></textarea>
        <div>
          <button type="submit">submit</button>
        </div>
        <p>Total number of character :{text.length}</p>
      </form>
      {Object.keys(eachCharResult).map((el, i) => (
        <p key={i}>{`${el}: ${eachCharResult[el]}`}</p>
      ))}
    </div>
  );
}

Ignoring space, you can solve like this:

const removeSpace = (text) => text.replace(/\s/g, '');

function Home() {
  const [text, setText] = useState('');

  const myFunction = (e) => {
    e.preventDefault();
    console.log('clicked');
  };

  const eachCharResult = useMemo(() => {
    let result = {};
    let textWithoutSpace = removeSpace(text);
    for (let i = 0; i < textWithoutSpace.length; i++) {
      if (result[textWithoutSpace[i]]) result[textWithoutSpace[i]]++;
      else result[textWithoutSpace[i]] = 1;
    }
    return result;
  }, [text]);

  return (
    <div>
      <form onSubmit={myFunction}>
        <h3>Please enter text</h3>
        <textarea
          onChange={(e) => setText(e.target.value)}
          placeholder="start typing"
        ></textarea>
        <div>
          <button type="submit">submit</button>
        </div>
        <p>Total number of character :{removeSpace(text).length}</p>
      </form>
      {Object.keys(eachCharResult).map((el, i) => (
        <p key={i}>{`${el}: ${eachCharResult[el]}`}</p>
      ))}
    </div>
  );
}
Andara
  • 565
  • 3
  • 10
  • 1
    Thank you. Can we select or highlight most repeated words like any four or five most frequent character? – Notation Nov 02 '21 at 03:39
  • 1
    yeah sure, you can achieve that by manipulating this `eachCharResult` – Andara Nov 02 '21 at 03:42
  • do we check each character in function ? can you update that in the code ? – Notation Nov 02 '21 at 03:43
  • I was wondering same like how can we highlight the most repeated character like the 5 most frequent characters in the text. –  Nov 02 '21 at 03:50
  • 1
    for that I think you should make another thread question, share the link and I'll help you there :) – Andara Nov 02 '21 at 03:54
  • Here is the link for the question https://stackoverflow.com/questions/69805242/how-to-highlight-most-frequent-character-in-the-text-from-texarea-using-reactjs – Notation Nov 02 '21 at 03:58
  • @Andara Why does numbers shows first if it is in the middle of text ? eg: if user input `aaabb111cc` it show `1:3,a:3,b:2,c:2` isn't it suppose to show `a:3,b:2,1:3,c:2` ? if it is counting order wise character. –  Nov 03 '21 at 01:15
0

Maybe something like this (I didn't run it)

import React, { useState } from "react";

// new
const alphabet = 'abcdefghijklmnopqrstuvwxyz'
const counts = {}
alphabet.split('').forEach(letter => counts[letter] = 0)

function Home() {
  const [characterCount, setCharacterCount] = useState(0);

  // new 
  const [letterCount, setLetterCount] = useState(counts)

  // new 
  const onTextChange = e => {
      setCharacterCount(e.target.value.length)

      // update count for letter
      const l = e.target.value[e.target.value.length -1]
      letterCount[l] += 1
      setLetterCount(letterCount)
  }

  const myFunction = (e) => {
    e.preventDefault();
    console.log("clicked");
  };
  return (
    <div>
      <form onSubmit={myFunction}>
        <h3>Please enter text</h3>
        <textarea
          onChange={(e) => onTextChange(e)}  // <-- new
          placeholder="start typing"
        ></textarea>
        <div>
          <button type="submit">submit</button>
        </div>
        <p>Total number of character :{characterCount}</p>
        {
            // new
            Object.keys(letterCount).map(li => {
                 return <p key={`key-${li}`>{li}: {letterCount[li]}</p>
            })

      }

      </form>
    </div>
  );
}

export default Home;
sin tribu
  • 1,148
  • 1
  • 6
  • 14
  • Okay, I updated the key, the other problem should be easy to figure out. Rewrite ```onTextChange``` to subtract instead of add depending on if they are adding or removing. You already have the length if that helps. – sin tribu Nov 02 '21 at 03:12
  • It add total count if i delete the same character like if user enter `aa` and remove `aa` then it displays total count of `a=4` also it shows `: NaN undefined : NaN` at the end of list. – Notation Nov 02 '21 at 03:17
0

Check that solution, got the character count function here.

function Char_Count(str1) {
  let chars = {};
  str1.replace(/\S/g, function (l) {
    chars[l] = isNaN(chars[l]) ? 1 : chars[l] + 1;
  });
  return chars;
}

function Home() {
  const [characterCount, setCharacterCount] = useState({});

  const onTextAreaChange = (e) => {
    setCharacterCount(Char_Count(e.target.value));
  };

  const myFunction = (e) => {
    e.preventDefault();
    console.log("clicked");
  };
  return (
    <div>
      <form onSubmit={myFunction}>
        <h3>Please enter text</h3>
        <textarea
          onChange={onTextAreaChange}
          placeholder="start typing"
        ></textarea>
        <div>
          <button type="submit">submit</button>
        </div>
        <p>All character counts:</p>
        {Object.keys(characterCount).map((item, i) => (
          <p key={i}>
            {item}: {characterCount[item]}
          </p>
        ))}
      </form>
    </div>
  );
}

If we want to sort the characterCount object based on the most repeated character, we can update the onTextAreaChange to this:

  const onTextAreaChange = (e) => {
    const countObj = Char_Count(e.target.value);
    const sortableCountObj = Object.entries(countObj)
      .sort(([, a], [, b]) => b - a)
      .reduce((r, [k, v]) => ({ ...r, [k]: v }), {});

    setCharacterCount(sortableCountObj);
  };

Edit react-count-each-character

Rakib
  • 170
  • 2
  • 14
  • I have one question how do you select or highlight most repeated words like any four or five most frequent character? –  Nov 02 '21 at 03:47
  • @Sprug We can sort the `characterCount` object I think. Got the hint [here](https://stackoverflow.com/a/1069840/5041988). I have updated the answer and CodeSandbox, please check. – Rakib Nov 02 '21 at 04:07
  • Why does numbers shows first if it is in the middle of text ? eg: if user input `aaabb111cc` it show `1:3,a:3,b:2,c:2` isn't it suppose to show `a:3,b:2,1:3,c:2` ? if it is counting order wise character –  Nov 03 '21 at 01:28
  • It is counting/sorting based on the most frequent characters, not order wise. However, it seems not to sort the numbers properly. The reason is after sorting, we are converting the sorted array to an object. I found Javascript always puts number keys at first! – Rakib Nov 03 '21 at 04:01