[java] 줄 단위로 문자열 읽기

너무 길지 않은 문자열이 있다면 한 줄씩 읽는 가장 좋은 방법은 무엇입니까?

나는 네가 할 수 있다는 것을 안다.

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

다른 방법은 eol에서 하위 문자열을 가져 오는 것입니다.

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

다른 간단한 방법이 있습니까? 위의 접근 방식에는 아무런 문제가 없으며 간단하고 효율적으로 보일 수있는 것을 알고 있다면 관심이 있습니까?



답변

splitString 의 메소드를 사용할 수도 있습니다 .

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

이것은 모든 배열을 편리한 배열로 제공합니다.

분할 성능에 대해 모르겠습니다. 정규식을 사용합니다.


답변

또한 있습니다 Scanner. 다음과 같이 사용할 수 있습니다 BufferedReader.

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

나는 이것이 제안 된 두 가지보다 조금 더 깨끗한 접근법이라고 생각합니다.


답변

특히 효율성 각도에 관심이 있었기 때문에 약간의 테스트 클래스를 만들었습니다 (아래). 5,000,000 줄의 결과 :

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

평소와 같이 정확한 시간은 다를 수 있지만 비율은 사실이지만 자주 실행합니다.

결론 : OP의 “단순”및 “보다 효율적인”요구 사항을 동시에 만족시킬 수는 없으며 split솔루션 (단 하나의 구현)이 더 단순하지만 Reader구현이 다른 쪽보다 우선합니다.

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();
    }
}


답변

Apache Commons IOUtils 를 사용하면 다음을 통해 멋지게 수행 할 수 있습니다

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

영리한 일을하지는 않지만 훌륭하고 컴팩트합니다. 스트림도 처리 할 수 ​​있으며 LineIterator원하는 경우 더 얻을 수도 있습니다 .


답변

솔루션 사용 Java 8등의 기능 Stream APIMethod references

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

또는

public void someMethod(String myLongString) {

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

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


답변

Java 11부터는 새로운 방법이 있습니다 String.lines.

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

용법:

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


답변

Java 8에서 lines () 스트림 출력을 얻은 BufferedReader로 래핑 된 스트림 API 및 StringReader를 사용할 수 있습니다.

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)
        );
    }
}

준다

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

BufferedReader의 readLine에서와 같이, 개행 문자 자체는 포함되지 않습니다. 모든 종류의 줄 바꾸기 구분 기호가 지원됩니다 (같은 문자열에서도).