逐行读取字符串

His*_*His 135 java string

给定一个不太长的字符串,逐行读取它的最佳方法是什么?

我知道你可以这样做:

BufferedReader reader = new BufferedReader(new StringReader(<string>));
reader.readLine();
Run Code Online (Sandbox Code Playgroud)

另一种方法是在eol上获取子字符串:

final String eol = System.getProperty("line.separator");
output = output.substring(output.indexOf(eol + 1));
Run Code Online (Sandbox Code Playgroud)

这样做还有其他更简单的方法吗?我对上述方法没有任何问题,只想知道你们中是否有人知道看起来更简单,更有效的东西?

not*_*oop 193

还有Scanner.您可以像以下一样使用它BufferedReader:

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

我认为这对于两个建议的方法都是一种更清洁的方法.

  • 完成阅读后不要忘记关闭扫描仪. (13认同)
  • 我不认为这是一个公平的比较 - String.split依赖于整个输入被读入内存,这并不总是可行的(例如对于大文件). (5认同)
  • 如果输入是String,则输入必须驻留在内存中.内存开销是数组.此外,生成的字符串重用相同的后端字符数组. (3认同)
  • 请注意,如果您扫描包含 Unicode 字符的 UTF-8 文件并且未在 Scanner 中指定编码,则 Scanner 可能会产生错误的结果。它可能会将不同的字符解释为行尾。在 Windows 中它使用默认编码。 (2认同)

ftl*_*ftl 126

您还可以使用splitString 的方法:

String[] lines = myString.split(System.getProperty("line.separator"));
Run Code Online (Sandbox Code Playgroud)

这为您提供了方便的数组中的所有行.

我不知道拆分的表现.它使用正则表达式.

  • "line.separator"无论如何都不可靠.仅仅因为代码在(例如)Unix上运行,是什么阻止文件使用Windows风格的"\ r \n"行分隔符?BufferedReader.readLine()和Scanner.nextLine()始终检查所有三种样式的分隔符. (45认同)
  • 我知道这个评论真的很旧,但是......问题根本没有提到文件.假设没有从文件中读取字符串,这种方法可能是安全的. (5认同)
  • 并希望行分隔符中没有正则表达式字符.:) (3认同)

Are*_*end 39

由于我对效率角度特别感兴趣,我创建了一个小测试类(如下).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
Run Code Online (Sandbox Code Playgroud)

像往常一样,确切的时间可能会有所不同,但这个比例是正确的,但是我经常运行它.

结论: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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 从Java8开始,BufferedReader有一个`lines()`函数返回行的`Stream <String>`,如果你愿意,你可以将它们收集到一个列表中,或者处理流. (4认同)

Bri*_*new 22

使用Apache Commons IOUtils,你可以很好地通过

List<String> lines = IOUtils.readLines(new StringReader(string));
Run Code Online (Sandbox Code Playgroud)

它没有做任何聪明的事情,但它很好而且紧凑.它也会处理流,LineIterator如果您愿意,也可以获得.

  • 这种方法的一个缺点是`IOUtils.readlines(Reader)`抛出一个`IOException`.尽管使用StringReader可能永远不会发生这种情况,但您必须捕获或声明它. (2认同)

Bat*_*aev 14

使用和Java 8等功能的解决方案Stream APIMethod references

new BufferedReader(new StringReader(myString))
        .lines().forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

要么

public void someMethod(String myLongString) {

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

private void parseString(String data) {
    //do something
}
Run Code Online (Sandbox Code Playgroud)


Zhe*_*lov 8

从Java 11开始,有一种新方法String.lines:

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

用法:

"line1\nline2\nlines3"
    .lines()
    .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)


mas*_*ilo 7

您可以使用流api和包裹在BufferedReader中的StringReader来获取Java 8中的lines()流输出:

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)
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

就像在BufferedReader的readLine中一样,不包含换行符。支持各种换行符(甚至在同一字符串中)。


Oli*_*and 6

您还可以使用:

String[] lines = someString.split("\n");
Run Code Online (Sandbox Code Playgroud)

如果不行请尝试更换\n\r\n.

  • 对换行符的表示进行硬编码使得解决方案依赖于平台. (2认同)

小智 5

或者使用新的 try with resources 子句结合 Scanner:

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