简体   繁体   English

遍历 Java 字符串行的最佳方法是什么?

[英]What is the best way to iterate over the lines of a Java String?

Currently I'm using something like:目前我正在使用类似的东西:

String[]lines = textContent.split(System.getProperty("line.separator"));
for(String tmpLine : lines){
   //do something
}

I'm not very glad of this method because it create an heavy array (let say textContent can contain a book).我不太喜欢这种方法,因为它创建了一个沉重的数组(假设textContent可以包含一本书)。

Is there any better solution to iterate over the lines of a String ?是否有更好的解决方案来遍历String的行?

You could use :你可以使用:

BufferedReader bufReader = new BufferedReader(new StringReader(textContent));

And use the readLine() method :并使用readLine()方法:

String line=null;
while( (line=bufReader.readLine()) != null )
{

}

To add the Java 8 way to this question:将 Java 8 方式添加到这个问题:

Arrays.stream(content.split("\\r?\\n")).forEach(line -> /*do something */)

Of curse you can also use System.lineSeparator() to split if you are sure that the file is comming from the same plattform as the vm runs on.当然,如果您确定文件来自与 vm 运行的同一平台,您也可以使用System.lineSeparator()进行拆分。

Or even better use the stream api even more agressiv with filter, map and collect:或者甚至更好地使用带有过滤器、映射和收集功能的流 api,甚至更多:

String result = Arrays.stream(content.split(System.lineSeparator()))
                     .filter(/* filter for lines you are interested in*/)
                     .map(/*convert string*/)
                     .collect(Collectors.joining(";"));

I believe you have a better API available starting with Java-11 where you can do the same using the String.lines() API which returns the stream of strings extracted from this string partitioned by line terminators.我相信从 Java-11 开始,你有一个更好的 API 可用,你可以使用String.lines() API 来做同样的事情,它返回从这个字符串中提取的字符串流,由行终止符分区。

public Stream<String> lines()

Usage of the same could be:-相同的用法可能是:-

Stream<String> linesFromString = textContent.lines();
linesFromString.forEach(l -> {  //do sth });

Important API Note :-重要的 API 说明:-

@implNote This method provides better performance than
          split("\R") by supplying elements lazily and
          by faster search of new line terminators.

You could use String.indexOf()/String.substring()你可以使用 String.indexOf()/String.substring()

String separator = System.getProperty("line.separator");
int index = textContent.indexOf(separator);

while (index > 0)
{
  int nextIndex = textContent.indexOf(separator, index + separator.length());
  String line = textContent.substring(index + separator.length(), nextIndex);

  // do something with line.
}

Scanner

What about the java.util.Scanner class added in Java 1.5? Java 1.5 java.util.Scanner添加的java.util.Scanner类怎么样?

In summary:总之:

A simple text scanner which can parse primitive types and strings using regular expressions.一个简单的文本扫描器,可以使用正则表达式解析原始类型和字符串。

A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace. Scanner 使用分隔符模式将其输入分解为标记,默认情况下与空格匹配。 The resulting tokens may then be converted into values of different types using the various next methods.然后可以使用各种 next 方法将结果令牌转换为不同类型的值。

and of note for your scenario:并注意您的场景:

The scanner can also use delimiters other than whitespace.扫描仪还可以使用空格以外的分隔符。 This example reads several items in from a string:此示例从字符串中读取多个项目:

 String input = "1 fish 2 fish red fish blue fish"; Scanner s = new Scanner(input).useDelimiter("\\\\s*fish\\\\s*"); System.out.println(s.nextInt()); System.out.println(s.nextInt()); System.out.println(s.next()); System.out.println(s.next()); s.close();

Guava's Splitter works well. Guava 的Splitter效果很好。 Especially as you can remove blank lines特别是因为您可以删除空行

Splitter splitter = Splitter.on(System.getProperty("line.separator"))
                            .trimResults()
                            .omitEmptyStrings();
for (String line : splitter.split(input)){
   // do work here
}

You can actually wrangle Scanner to allow you to use a normal for loop:您实际上可以使用Scanner来允许您使用正常的for循环:

import java.util.Scanner;
public class IterateLines {
    public static void main(String[] args) {
        Iterable<String> sc = () ->
            new Scanner("foo bar\nbaz\n").useDelimiter("\n");
        for (String line: sc) {
            System.out.println(line);
        }
    }
}

gives us:给我们:

$ javac IterateLines.java && java IterateLines 
foo bar
baz

If you are using Java 1.8 (or Android) then try this:如果您使用的是 Java 1.8(或 Android),请尝试以下操作:

new BufferedReader(new StringReader(str)).lines().forEachOrdered((line) -> {
    // process each line as you like
});

Docs state 文档状态

The Stream is lazily populated, ie, read only occurs during the terminal stream operation. Stream 是惰性填充的,即只读发生在终端流操作期间。

Which means this runs quicker than other solutions that first generate a massive array of Strings before iteration can begin.这意味着这比在迭代开始之前首先生成大量字符串的其他解决方案运行得更快。

If you are using Java 11 or later then the answer @Naman gave recommending String#lines() method is even cleaner and fast as well, see https://stackoverflow.com/a/50631579/215266如果您使用的是 Java 11 或更高版本,那么@Naman 给出的答案推荐String#lines()方法甚至更清晰、更快速,请参阅https://stackoverflow.com/a/50631579/215266

结合java.io.StringReaderjava.io.LineNumberReader

use BufferedReader with StringReader argument.将 BufferedReader 与 StringReader 参数一起使用。 BufferedReader has a method readLine() so you can read your string line by line. BufferedReader 有一个 readLine() 方法,因此您可以逐行读取您的字符串。

    StringReader reader = new StringReader(myBigTextString);
    BufferedReader br = new BufferedReader(reader);
    String line;
    while((line=br.readLine())!=null)
    {
        //do what you want
    }

You could use:你可以使用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM