I can't figure out why my JavaScript recursion function isn't correctly counting the number of lines, words, and characters in a text

Seeking assistance with my JavaScript recursion program that is not functioning as expected. The goal is to extract words from a text file and output the count of words, lines, and characters. I am uncertain where my mistake lies, so any guidance on code modification would be greatly appreciated. Below is the JavaScript code in question:

var fs = require("fs");
var text = fs.readFileSync("text.txt", "utf8");
function countLines(text) {
  if (text == "") {
    return 0;
  } else {
    return 1 + countLines(text.substring(text.indexOf("\n") + 1));
  }
}
function countWords(text) {
  if (text == "") {
    return 0;
  } else {
    return 1 + countWords(text.substring(text.indexOf(" ") + 1));
  }
}
function countCharacters(text) {
  if (text == "") {
    return 0;
  } else {
    return 1 + countCharacters(text.substring(1));
  }
}
var lineCount = countLines(text);
var wordCount = countWords(text);
var characterCount = countCharacters(text);
console.log(
  "There are " +
    lineCount +
    " lines, " +
    wordCount +
    " words, and " +
    characterCount +
    " characters in the file."
);

Below is the content of the text.txt file:

I was running to the zoo.

Answer №1

When it comes to counting lines, the key condition is not checking for an empty string with if (text == ""), but rather determining if there is no \n present in the text. By adjusting the base case, we open up new perspectives on the issue and streamline our code.

Assuming i represents the position of \n in the string text -

  1. If i is negative, then text constitutes the final line. In this scenario, the function should return 1.
  2. (inductive) If i is 0 or greater, it implies that text encompasses multiple lines. In such cases, the function should return 1 plus the outcome of the sub-problem.

function countLines(text) {
  const i = text.indexOf("\n")
  if (i < 0) return 1                                // 1
  else return 1 + countLines(text.substring(i + 1))  // 2
}

console.log(countLines(`Hello`))

console.log(countLines(`Hello
World,`))

console.log(countLines(`Hello
World,
We don't deserve you.`))

An alternative approach is to use a ternary expression for a more concise implementation -

function countLines(text) {
  const i = text.indexOf("\n")
  return (i < 0) ? 1 : 1 + countLines(text.substring(i + 1))
}

Answer №2

Your problem arises from a blind recursion that does not check the result of indexOf, which returns -1 if the target is not found

thus

text.substring(text.indexOf(" ") + 1)

turns into

text.substring(-1 + 1)

which is equivalent to

text.substring(0)

This results in infinite recursion for the last word (and line)

If .indexOf returns -1, you should return 1

Note: I have removed the unnecessary else in the code - absence of else when the if returns a value leads to cleaner code (although you can use else if needed

I have demonstrated two approaches to test indexOf

var text = "I was running to the zoo.";

function countLines(text) {
  if (text == "") {
    return 0;
  }
  const index = text.indexOf("\n");
  if (index  < 0) {
    return 1;
  }
  return 1 + countLines(text.substring(index + 1));
}

function countWords(text) {
  if (text == "") {
    return 0;
  }
  const index = text.indexOf(" ") + 1;
  if (index) { // since we've added 1, a "not found" -1 would be 0 here, and be falsey
    return 1 + countWords(text.substring(index));
  }
  return 1;
}

function countCharacters(text) {
  if (text == "") {
    return 0;
  } 
  return 1 + countCharacters(text.substring(1));
}
var lineCount = countLines(text);
var wordCount = countWords(text);
var characterCount = countCharacters(text);
console.log(
  "There are " +
  lineCount +
  " lines, " +
  wordCount +
  " words, and " +
  characterCount +
  " characters in the file."
);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Data in the array is only updated upon refreshing the webpage

Why is the array empty when I navigate to a new route (/category/name-of-category) that renders my Category component, but it gets data when I refresh the page? What am I missing here? To better explain, I have created a video. Video showcasing the issue: ...

Data that is loaded asynchronously will not display rendered

I have async data loading via jayson from a server. After the data has finished loading, the boolean "loading" is set to false but my content does not re-render. Even though I can see on the console that the data was loaded correctly. var App = new Vue( ...

Retrieving data from a textbox using JavaScript within an Excel VBA setting

I'm encountering an issue with a Macro in Excel where I need to retrieve the value of an "input type="text"" on a JavaScript webpage. However, the value is not specified in the code (value=""), and it remains unchanged even when the webpage displays t ...

The Datalist feature in HTML5 offers an auto-suggest functionality that displays a list of options beginning with the

In my project, I am utilizing HTML5 Datalist for autosuggestion. By default, HTML5 follows the keyword contains approach rather than the starts with approach. For example, if my datalist includes one, two, three and I type "o" in the search box, it displ ...

What is the correct method for notifying the progress of time using jQuery?

I'm looking for a way to display the processing time of my PHP code using jQuery Here's an example of my PHP code : <?php //some queries to database ?> Below is my jQuery code: $.ajax({ type: "POST", url: "action. ...

Is there a way to transfer the functionality of openssl_seal from PHP to NodeJS 18?

I'm looking to convert the openssl_seal() function from PHP to NodeJs. The code below is from my PHP SDK and works flawlessly, which is what I want to migrate: $ivLength = openssl_cipher_iv_length('AES-256-CBC') ?: 16; $iv = openssl_random ...

Are you experiencing issues with your Ajax request?

I've been struggling to retrieve json data from an API. Despite my efforts, the GET request seems to be executing successfully and returning the correct data when I check the Net tab in Firebug. Can anyone offer advice on what could be going wrong or ...

Storing data in Angular service for future use

My ui-grid is functioning correctly, utilizing server side pagination with a view button to display row details on a separate page. However, upon returning to the grid after viewing details, it defaults back to displaying the first page. I would like it to ...

How can the token be verified when authorizing Google OAuth 2.0 on the server side?

Unable to validate the user token ID on the server side despite following Google's guide at https://developers.google.com/identity/sign-in/web/backend-auth In JavaScript, I retrieve the id token and send it to the server: var googleUser = auth2.cur ...

What does Angular classify as a watcher?

What qualifies as "watchers" within Angular? Are watchers the only type of monitoring mechanism, or do other Angular elements like ngModel also serve as watchers? Am I overlooking something crucial? For example, do watchers play a role in enabling directi ...

I'm struggling with an issue of being undefined in my React.js project

This code snippet is from my app.js file import React, { useState, useEffect } from "react"; import { v4 as uuid } from "uuid"; import "./App.css"; import Header from "./Header"; import AddContact from "./AddCo ...

I am curious to see the number of people who have made their selection

I am currently using JavaScript to alter the text value from "select" to "selected". My next step is to include the selected text in a cart. Can you please provide some guidance? Thank you in advance. PHP CODE : <a class='btn slct' href=&ap ...

RXJS - Trigger a function based on a specific condition being fulfilled by a value emitted from an observable

I have created a search field with autocomplete functionality. By using an observable that monitors changes in the text field, I am able to trigger actions based on user input. this.term.valueChanges .debounceTime(300) .distinctUntilChange ...

Firebase (web) deploy encounters an issue due to stripe integration

I recently integrated Stripe into my Firebase function index.js: const stripe = require('stripe')('key'); and created a function for checkout sessions: exports.createCheckoutSession = functions.https.onCall(async(data, context) =&g ...

Configuring Proxy Settings for WebpackDevServer

I need assistance setting up a proxy using WebpackDevServer in my React/Node chrome extension. Currently, my server is running on localhost:4000, and the React frontend is on localhost:5000. When trying to access the route /api/user/ticket using Axios, I ...

Loading an OBJ file from a blob using three.js

I am currently attempting to load an OBJ file from a blob using Three.js. After referring to this resource and successfully loading STL files, I encountered an issue with loading OBJ files. The error message I received is as follows: TypeError: text.indexO ...

Using Vue.js to loop through data objects when a button is clicked

I'm currently working on building a quiz functionality using vue.js, but I've hit a roadblock in trying to make the "Next" button cycle through my data. The goal is to have the screen display the object containing the question and answers (e.g. q ...

Trouble with transmitting props to function

The child component is not receiving the props as expected. When printed, it displays an empty object. The problem seems to be in the News.js file specifically related to passing props to the child component from App.js. All functions are operational excep ...

Issue with rendering partials in ExpressHandlebars in NodeJS

I am currently facing an issue while working with express-handlebars. I am attempting to use partials, but I keep encountering the following error message: The partial header could not be found. In my app.js file, the code appears as follows: var expr ...

Is Performance Enhanced by Exporting Meshes in Three.js?

Currently, I am working on a Three.js project and have noticed some performance lag in certain areas. The most significant lag occurs when rendering the text Meshes that I have created as follows: var text1Geo = new THREE.TextGeometry("Hello", {font: font ...