Read String line by line

JavaString

Java Problem Overview


Given a string that isn't too long, what is the best way to read it line by line?

I know you can do:

BufferedReader reader = new BufferedReader(new StringReader(<string>));
reader.readLine();

Another way would be to take the substring on the eol:

final String eol = System.getProperty("line.separator");
output = output.substring(output.indexOf(eol + 1));

Any other maybe simpler ways of doing it? I have no problems with the above approaches, just interested to know if any of you know something that may look simpler and more efficient?

Java Solutions


Solution 1 - Java

There is also Scanner. You can use it just like the BufferedReader:

Scanner scanner = new Scanner(myString);
while (scanner.hasNextLine()) {
  String line = scanner.nextLine();
  // process the line
}
scanner.close();

I think that this is a bit cleaner approach that both of the suggested ones.

Solution 2 - Java

You can also use the split method of String:

String[] lines = myString.split(System.getProperty("line.separator"));

This gives you all lines in a handy array.

I don't know about the performance of split. It uses regular expressions.

Solution 3 - Java

Since I was especially interested in the efficiency angle, I created a little test class (below). Outcome for 5,000,000 lines:

Comparing line breaking performance of different solutions
Testing 5000000 lines
Split (all): 14665 ms
Split (CR only): 3752 ms
Scanner: 10005
Reader: 2060

As usual, exact times may vary, but the ratio holds true however often I've run it.

Conclusion: the "simpler" and "more efficient" requirements of the OP can't be satisfied simultaneously, the split solution (in either incarnation) is simpler, but the Reader implementation beats the others hands down.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Test class for splitting a string into lines at linebreaks
 */
public class LineBreakTest {
    /** Main method: pass in desired line count as first parameter (default = 10000). */
    public static void main(String[] args) {
        int lineCount = args.length == 0 ? 10000 : Integer.parseInt(args[0]);
        System.out.println("Comparing line breaking performance of different solutions");
        System.out.printf("Testing %d lines%n", lineCount);
        String text = createText(lineCount);
        testSplitAllPlatforms(text);
        testSplitWindowsOnly(text);
        testScanner(text);
        testReader(text);
    }

    private static void testSplitAllPlatforms(String text) {
        long start = System.currentTimeMillis();
        text.split("\n\r|\r");
        System.out.printf("Split (regexp): %d%n", System.currentTimeMillis() - start);
    }

    private static void testSplitWindowsOnly(String text) {
        long start = System.currentTimeMillis();
        text.split("\n");
        System.out.printf("Split (CR only): %d%n", System.currentTimeMillis() - start);
    }

    private static void testScanner(String text) {
        long start = System.currentTimeMillis();
        List<String> result = new ArrayList<>();
        try (Scanner scanner = new Scanner(text)) {
            while (scanner.hasNextLine()) {
                result.add(scanner.nextLine());
            }
        }
        System.out.printf("Scanner: %d%n", System.currentTimeMillis() - start);
    }

    private static void testReader(String text) {
        long start = System.currentTimeMillis();
        List<String> result = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new StringReader(text))) {
            String line = reader.readLine();
            while (line != null) {
                result.add(line);
                line = reader.readLine();
            }
        } catch (IOException exc) {
            // quit
        }
        System.out.printf("Reader: %d%n", System.currentTimeMillis() - start);
    }

    private static String createText(int lineCount) {
        StringBuilder result = new StringBuilder();
        StringBuilder lineBuilder = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            lineBuilder.append("word ");
        }
        String line = lineBuilder.toString();
        for (int i = 0; i < lineCount; i++) {
            result.append(line);
            result.append("\n");
        }
        return result.toString();
    }
}

Solution 4 - Java

Using Apache Commons IOUtils you can do this nicely via

List<String> lines = IOUtils.readLines(new StringReader(string));

It's not doing anything clever, but it's nice and compact. It'll handle streams as well, and you can get a LineIterator too if you prefer.

Solution 5 - Java

Solution using Java 8 features such as Stream API and Method references

new BufferedReader(new StringReader(myString))
        .lines().forEach(System.out::println);

or

public void someMethod(String myLongString) {

    new BufferedReader(new StringReader(myLongString))
            .lines().forEach(this::parseString);
}

private void parseString(String data) {
    //do something
}

Solution 6 - Java

Since Java 11, there is a new method String.lines:

/**
 * Returns a stream of lines extracted from this string,
 * separated by line terminators.
 * ...
 */
public Stream<String> lines() { ... }

Usage:

"line1\nline2\nlines3"
    .lines()
    .forEach(System.out::println);

Solution 7 - Java

You can also use:

String[] lines = someString.split("\n");

If that doesn't work try replacing \n with \r\n.

Solution 8 - Java

You can use the stream api and a StringReader wrapped in a BufferedReader which got a lines() stream output in java 8:

import java.util.stream.*;
import java.io.*;
class test {
    public static void main(String... a) {
        String s = "this is a \nmultiline\rstring\r\nusing different newline styles";

        new BufferedReader(new StringReader(s)).lines().forEach(
            (line) -> System.out.println("one line of the string: " + line)
        );
    }
}

Gives

one line of the string: this is a
one line of the string: multiline
one line of the string: string
one line of the string: using different newline styles

Just like in BufferedReader's readLine, the newline character(s) themselves are not included. All kinds of newline separators are supported (in the same string even).

Solution 9 - Java

Or use new try with resources clause combined with Scanner:

   try (Scanner scanner = new Scanner(value)) {
		while (scanner.hasNextLine()) {
			String line = scanner.nextLine();
			// process the line
		}
	}

Solution 10 - Java

You can try the following regular expression:

\r?\n

Code:

String input = "\nab\n\n    \n\ncd\nef\n\n\n\n\n";
String[] lines = input.split("\\r?\\n", -1);
int n = 1;
for(String line : lines) {
	System.out.printf("\tLine %02d \"%s\"%n", n++, line);
}

Output:

Line 01 ""
Line 02 "ab"
Line 03 ""
Line 04 "    "
Line 05 ""
Line 06 "cd"
Line 07 "ef"
Line 08 ""
Line 09 ""
Line 10 ""
Line 11 ""
Line 12 ""

Solution 11 - Java

The easiest and most universal approach would be to just use the regex Linebreak matcher \R which matches Any Unicode linebreak sequence:

Pattern NEWLINE = Pattern.compile("\\R")
String lines[] = NEWLINE.split(input)

@see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHisView Question on Stackoverflow
Solution 1 - JavanotnoopView Answer on Stackoverflow
Solution 2 - JavaftlView Answer on Stackoverflow
Solution 3 - JavaArendView Answer on Stackoverflow
Solution 4 - JavaBrian AgnewView Answer on Stackoverflow
Solution 5 - JavaBatiaevView Answer on Stackoverflow
Solution 6 - JavaZhekaKozlovView Answer on Stackoverflow
Solution 7 - JavaOlin KirklandView Answer on Stackoverflow
Solution 8 - JavamasterxiloView Answer on Stackoverflow
Solution 9 - JavaMārcisView Answer on Stackoverflow
Solution 10 - JavaPaul VargasView Answer on Stackoverflow
Solution 11 - JavarednoahView Answer on Stackoverflow