7

I have a need to loop through a large string with several eol characters and read each of these lines looking for characters. I could've done the following but I feel that its not very efficient as there could be more than 5000 characters in this large string.

var str = largeString.split("\n");

and then loop through str as an array

I cant really use jquery and can only use simple JavaScript.

Is there any other efficient way of doing this?

Nimantha
  • 6,405
  • 6
  • 28
  • 69
nixgadget
  • 6,983
  • 16
  • 70
  • 103
  • hmmm...you can use web workers, you can parse string in the background. http://www.w3schools.com/html/html5_webworkers.asp – StaleMartyr Nov 04 '13 at 03:18
  • what about using a regular expression? – l2mt Nov 04 '13 at 03:21
  • 5
    This should work just fine - there is no obvious way to do it simpler. 5000 characters is nothing for a modern computer, even a smartphone. Do you have some evidence that this is too slow? – jfriend00 Nov 04 '13 at 03:24
  • 5000 is just a minimum number I'm expecting. but it could well be 100000 characters. i realize theres no other efficient way of achieving this. for e.g. in java theres StringReader for this purpose. – nixgadget Nov 04 '13 at 03:46

6 Answers6

6

You could always use indexOf and substring to take each line of the string.

var input = 'Your large string with multiple new lines...';
var char = '\n';
var i = j = 0;

while ((j = input.indexOf(char, i)) !== -1) {
  console.log(input.substring(i, j));
  i = j + 1;
}

console.log(input.substring(i));

Edit I didn't see this question was so old before answering. #fail

Edit 2 Fixed code to output final line of text after last newline character - thanks @Blaskovicz

fubar
  • 16,918
  • 4
  • 37
  • 43
  • As someone who's having the same question in 2017, I'm glad you posted this answer in spite of the old question, it's the best one so far – osvein Sep 30 '17 at 22:51
  • 1
    Also, for the people reading this, remember that this won't get the trailing characters like `input.split(char)` would if their is no ending delimitter. If you need to do that, you can just check if `input.length === i` (meaning there were no trailing characters). – Blaskovicz Apr 24 '18 at 18:05
2

5000 doesn't seem that intense for a modern JavaScript engine. Of course it depends on what you do on each iteration too. For clarity I recommend using eol.split and [].forEach.

eol is an npm package. In Node.js and CommonJS you can npm install eol and require it. In ES6 bundlers you can import. Otherwise loaded via <script> eol is global

// Require if using Node.js or CommonJS
const eol = require("eol")

// Split text into lines and iterate over each line like this
let lines = eol.split(text)
lines.forEach(function(line) {
  // ...
})
ryanve
  • 50,076
  • 30
  • 102
  • 137
  • First line produce exception: Uncaught ReferenceError: require is not defined – Leonid Mednikov May 20 '18 at 13:21
  • Also split works exactly opposite ot the example. The correct version is: string.split(symbolForSplitting) – Leonid Mednikov May 20 '18 at 13:25
  • @LeonidMednikov Answer clarified. `require` is for Node.js or CommonJS. Otherwise skip that line. `eol.split` is a library method different from `"".split`. Next time please consider asking questions before downvoting without understanding : ) – ryanve May 21 '18 at 20:31
2

If you are using NodeJS, and have a large string to process line-by-line:

const Readable = require('stream').Readable
const readline = require('readline')

promiseToProcess(aLongStringWithNewlines) {
    //Create a stream from the input string
    let aStream = new Readable();
    aStream.push(aLongStringWithNewlines);
    aStream.push(null);  //This tells the reader of the stream, you have reached the end

    //Now read from the stream, line by line
    let readlineStream = readline.createInterface({
      input: aStream,
      crlfDelay: Infinity
    });

    readlineStream.on('line', (input) => {
      //Each line will be called-back here, do what you want with it...
      //Like parse it, grep it, store it in a DB, etc
    });

    let promise = new Promise((resolve, reject) => {
      readlineStream.on('close', () => {
        //When all lines of the string/stream are processed, this will be called
        resolve("All lines processed");
      });
    });

    //Give the caller a chance to process the results when they are ready
    return promise;
  }
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Sagan
  • 2,033
  • 2
  • 14
  • 12
0

You could read it character by character manually and call a handler when you get a newline. It is unlikely to be more efficient in terms of CPU usage but will likely take up less memory. However, as long as the string is less than a few MBs, it should not matter.

0
function findChar(str, char) {
    for (let i = 0; i < str.length; i++) {
        if (str.charAt(i) == char) {
            return i
        }
    }
    return -1
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
-1

So, you know how to do it, you're just making sure there's no better way to do it? Well, I'd have to say the way you've mentioned is exactly it. Although you may want to look up a regex match if you're looking for certain text split by certain characters. A JS Regex Reference can be found Here

This would be useful if you know how the text is going to be setup, something akin to

var large_str = "[important text here] somethign something something something [more important text]"
var matches = large_str.match(\[([a-zA-Z\s]+)\])
for(var i = 0;i<matches.length;i++){
   var match = matches[i];
   //Do something with the text
}

Otherwise, yes, the large_str.split('\n') method with a loop is probably best.

Jhecht
  • 4,407
  • 1
  • 26
  • 44
  • A regex is very unlikely to be faster than `.split()`. Also, I don't think this will work because `\s` includes `\n` do it won't break on line boundaries. – jfriend00 Nov 04 '13 at 03:30
  • Considering I don't know how he's going to be looking for it, I gave him what I could. If I knew more, I could help more. I suppose he could `.split()` something and then use a regex per string to find whatever it was he wanted. – Jhecht Nov 04 '13 at 03:43