我遇到了Streams的DropWhile
或TakeWhile
方法的问题,因为spliterator跳过特定模式(奇数或偶数)的文本部分。应该做什么来处理文本的所有部分?我在这里的方法:
void read(Path filePath) {
try {
Stream<String> lines = Files.lines(filePath);
while (true) {
Spliterator<String> spliterator = lines.dropWhile(line -> !line.startsWith("FAYSAL:")).spliterator();
Stream<String> portion = fetchNextPortion(spliterator);
if(spliterator.estimateSize() == 0)
break;
portion .forEach(System.out::println);
lines = StreamSupport.stream(spliterator, false);
}
lines.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private Stream<String> fetchNextPortion(Spliterator<String> spliterator) {
return StreamSupport.stream(spliterator, false)
.filter(this::isValidReportName)
.peek(System.out::println)
.findFirst()
.map( first -> Stream.concat(Stream.of(first),
StreamSupport.stream(spliterator, false).takeWhile(line -> !line.startsWith("FAYSAL:")))).orElse(Stream.empty());
}
示例输入为:
FAYSAL: 1
Some text here
Some text here
FAYSAL: 2
Some text here
Some text here
FAYSAL: 3
Some text here
Some text here
FAYSAL: 4
Some text here
Some text here
它将跳过Faysal:2和Faysal:4
应该做什么来处理文本的所有部分?
你可以选择一个不同的方法。
您的代码在我的计算机上产生了一个StackOverflowError(还有一个对FetchNextChunk
的调用,但是一个名为FetchNextPartition
的方法,所以我也不确定这一点),所以我没有尝试调试它,而是想出了一种不同的方法来拆分输入。鉴于我的方法在内存中包含整个字符串,它可能不适合较大的文件。我以后可能会用Streams开发出一个版本。
基本假设:您希望将输入文本分成几个部分,每个部分都以一个以“faysal:”开头的字符串开始。
这个想法与您的方法类似,但不是基于spliterator,也没有使用dropWhile。相反,它会找到以“faysal:”开头的第一个字符串(我假定这就是isValidReportName
所做的;方法的代码不在问题中),并将所有内容处理到下一部分开始。将找到的第一个元素添加为列表的第一个元素,然后将集合添加到以后可以使用的列表中。然后从原始列表中删除收集的行数。
完整代码:
import java.util.*;
import java.util.stream.Collectors;
class Main {
public static void main(String[] args) {
Main m = new Main();
System.out.println(m.partitionTextByStringStart(m.getString()));
}
private List<List<String>> partitionTextByStringStart(String text) {
List<List<String>> partitions = new ArrayList<>();
List<String> lines = Arrays.asList(text.split("\n"));
while (!lines.isEmpty()) {
String first = lines.stream().filter(this::isValidReportName).findFirst().orElse("This is prolly bad");
List<String> part = lines.stream().skip(1).takeWhile(l -> !l.startsWith("FAYSAL:")).collect(Collectors.toList());
part.add(0, first);
partitions.add(part);
lines = lines.subList(part.size(), lines.size());
}
return partitions;
}
private boolean isValidReportName(String x) {
return x.startsWith("FAYSAL:");
}
private String getString() {
return "FAYSAL: 1\n" +
"Some text here1\n" +
"Some text here1\n" +
"FAYSAL: 2\n" +
"Some text here2\n" +
"Some text here2\n" +
"FAYSAL: 3\n" +
"Some text here3\n" +
"Some text here3\n" +
"FAYSAL: 4\n" +
"Some text here4\n" +
"Some text here4";
}
}
(注意:我在这里使用了一个静态字符串,而不是文件读取来制作完整的代码示例;您可以相应地改编您的代码)
编辑:经过一些研究,我发现使用StreamEx(Github)(Maven)库将这些东西分组在流中是非常容易的。在这个答案中,我找到了一个关于streamex#groupruns
函数的注释,该函数正是这样做的:
private Stream<Stream<String>> partitionStreamByStringStart(Stream<String> lineStream) {
return StreamEx.of(lineStream).groupRuns((l1, l2) -> !l2.startsWith("FAYSAL:")).map(Collection::stream);
}
若要查看其工作情况,您可以添加
System.out.println(m.partitionStreamByStringStart(m.getStream()).map(
s -> s.collect(Collectors.toList())
).collect(Collectors.toList()));
到主函数和
private Stream<String> getStream() {
return Stream.of(getString().split("\n"));
}
在上面的完整代码示例的主类中的某个地方。
我只有一个具有大xml文件最后顺序的文件,而不是许多小xml文件。你能告诉我出了什么问题吗?太感谢你们了!
问题内容: 我有这样的输入文件: 所需的任务是按由特殊行分隔的部分读取文件,在这种情况下,该行为空行,例如[out]: 通过这样做,我一直在获得所需的输出: 但是,如果特殊行是以例如以下开头的行: 我必须这样做: 如果我允许拥有分隔符参数,则可以尝试以下操作: 但是有没有办法我不对所有可能的分隔符进行硬编码? 问题答案: 传递谓词怎么样? 用法:
作为映射器输出而生成的部件文件是否只作为part-m-00000、Part-m-00001等工作,从而表示第一个输入拆分、第二个输入拆分等等,它们是否按顺序生成??
拆分项目文件 到目前为止我们自定义了一个build.gradle和settings.gradle文件,随着你添加越来越多的子项目和任务到build.gradle中,代码的维护性将会下降。通过给每个子项目建立一个单独的build.gradle文件可以解决这个问题。 接下来我们在每个子项目的目录下创建一个build.gradle文件,目录如下: 现在你可以把构建逻辑从原先的build脚本中拆分开来放到
我在思考这个问题的答案:如何在任何Java映射实现上测试空键? 我的第一个想法是检查映射的键集的是否具有特征: JavaDoc说: 表示源保证遇到的元素不为空的特征值。(例如,这适用于大多数并发集合、队列和映射。) 在回答之前,我做了一些检查: 即使自然排序不允许空键,没有提供的的也没有此特性。 更令人惊讶的是,键集的s和本身不具有此特性。 我知道< code>spliterator()的结果。h