programing

문자열을 한 줄씩 읽다

procenter 2022. 8. 17. 23:25
반응형

문자열을 한 줄씩 읽다

너무 길지 않은 문자열이 주어진다면 한 줄씩 읽는 가장 좋은 방법은 무엇일까요?

다음을 수행할 수 있습니다.

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

또 다른 방법은 eol의 서브스트링을 취하는 것입니다.

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

다른 간단한 방법은 없나요?위의 접근법에는 문제가 없습니다.단순하고 효율적으로 보일 수 있는 방법을 알고 계십니까?

도 있습니다.이 기능을 그대로 사용할 수 있습니다.BufferedReader:

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

나는 이것이 둘 다 제안하는 것보다 좀 더 깨끗한 접근법이라고 생각한다.

를 사용할 수도 있습니다.split문자열 메서드:

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

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

나는 스플릿의 퍼포먼스를 모른다.정규 표현을 사용합니다.

특히 효율 각도에 관심이 있었기 때문에, 작은 테스트 클래스(아래)를 작성했습니다.500,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 API그리고.Method 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);

다음 항목도 사용할 수 있습니다.

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

그래도 문제가 해결되지 않으면 교체해 보십시오.\n와 함께\r\n.

stream api와 Java 8에서 lines() 스트림 출력을 얻은 BufferedReader로 랩된 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과 마찬가지로 줄바꿈 문자 자체는 포함되지 않습니다.모든 종류의 줄 바꿈 구분자가 지원됩니다(같은 문자열로).

또는 Scanner와 결합된 resources 절을 사용합니다.

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

다음 정규 표현을 사용해 볼 수 있습니다.

\r?\n

코드:

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

출력:

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 ""

가장 쉽고 보편적인 접근법은 정규식을 사용하는 것입니다.Linebreak matcher \R어느 쪽과 일치하는지Any Unicode linebreak sequence:

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

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

언급URL : https://stackoverflow.com/questions/1096621/read-string-line-by-line

반응형