-2

I am leaving this answer here because it took me about an hour+ to solve and I am hoping to help anyone else looking for a similar answer.

The question has a few parts that are all answered in separate SO posts:

  1. Read a text file in javascript
  2. Parse the text to get a space delimited string, excluding special characters, tabs, new lines, etc.
  3. Count the number of each word
  4. Display a list in descending order
James B
  • 432
  • 5
  • 22
  • It was suggested that this is a duplicate of https://stackoverflow.com/questions/18473326/javascript-break-sentence-by-words, however, reading a text file in javascript creates a vastly different "string" if you want to call it that, than a simple var of type String and deals with line breaks, returns, etc. This also is a 4 part question, of which the linked question is but a fraction of one of these four parts – James B Nov 23 '21 at 05:02

1 Answers1

0

Starting with an input that accepts a file and a function that will eventually sort our string, ezString:


return (
    <div>
      <input type="file" onChange={e => showFile(e)}/>
      {ezString ? getSortedArr() : null}
    </div>
  );

and a function to turn that file into text (with a useState var ezString)

const [ezString, setEzString] = useState(null)

const showFile = async (e) => {
    e.preventDefault()
    const reader = new FileReader()
    reader.onload = async (e) => {
      const file = e.target.result
      const goodString = file.replaceAll(/\s\s+/g, ' ')
        .replaceAll(/(\r\n|\r|\n)/g, ' ')
        .replaceAll(/[^a-zA-Z ]/g, "").toLowerCase()
      setEzString(goodString);
    };
    reader.readAsText(e.target.files[0])
  }

and a sorting function

const getSortedArr = () => {
  let wordArray = ezString.split(' ').filter(n => n)
  let wordCount = {};
  for (let word of wordArray) {
    if (wordCount[word]) {
      wordCount[word] = wordCount[word] + 1
    } else {
      wordCount[word] = 1
    }
  }
  let sortedArr = Object.entries(wordCount).sort((a, b) => b[1] - a[1])
  return sortedArr ? sortedArr.map(arr => {
    return (
      <div key={arr[0]}>
        <p style={{fontSize: 16}}>{arr[0]}: {arr[1]}</p>
      </div>)
  }) : null
}

With these parts we have the full component:

import React, {useState} from 'react'

const WordCounter = () => {

  const [ezString, setEzString] = useState(null)

  const showFile = async (e) => {
    e.preventDefault()
    const reader = new FileReader()
    reader.onload = async (e) => {
      const file = e.target.result
      const goodString = file.replaceAll(/\s\s+/g, ' ')
        .replaceAll(/(\r\n|\r|\n)/g, ' ')
        .replaceAll(/[^a-zA-Z ]/g, "").toLowerCase()
      setEzString(goodString);
    };
    reader.readAsText(e.target.files[0])
  }


  const getSortedArr = () => {
    let wordArray = ezString.split(' ').filter(n => n)
    let wordCount = {};
    for (let word of wordArray) {
      if (wordCount[word]) {
        wordCount[word] = wordCount[word] + 1
      } else {
        wordCount[word] = 1
      }
    }
    let sortedArr = Object.entries(wordCount).sort((a, b) => b[1] - a[1])
    return sortedArr ? sortedArr.map(arr => {
      return (
        <div key={arr[0]}>
          <p style={{fontSize: 16}}>{arr[0]}: {arr[1]}</p>
        </div>)
    }) : null
  }



  return (
    <div className="App">
      <input type="file" onChange={e => showFile(e)}/>
      {ezString ? getSortedArr() : null}
    </div>
  );
}

export default WordCounter;

Areas for improvement:

  • I'm terrible with regex, thus the terrible regex and the need to filter empty strings out of the wordArray
James B
  • 432
  • 5
  • 22