当前位置: 首页 > 知识库问答 >
问题:

在Java8流中有多个Regex从行中读取文本

井誉
2023-03-14

我想有一个以上的regex如下所示,我如何将其添加到flatmap迭代器中,以便在单个流读取期间将该行的所有匹配值列表?

static String reTimeStamp="((?:2|1)\\d{3}(?:-|\\/)(?:(?:0[1-9])|(?:1[0-2]))(?:-|\\/)(?:(?:0[1-9])|(?:[1-2][0-9])|(?:3[0-1]))(?:T|\\s)(?:(?:[0-1][0-9])|(?:2[0-3])):(?:[0-5][0-9]):(?:[0-5][0-9]))";
static String reHostName="host=(\\\")((?:[a-z][a-z\\.\\d\\-]+)\\.(?:[a-z][a-z\\-]+))(?![\\w\\.])(\\\")";
static String reServiceTime="service=(\\d+)ms";

private static final PatternStreamer quoteRegex1 = new PatternStreamer(reTimeStamp);
private static final PatternStreamer quoteRegex2 = new PatternStreamer(reHostName);
private static final PatternStreamer quoteRegex3 = new PatternStreamer(reServiceTime);


public static void main(String[] args) throws Exception {
    String inFileName = "Sample.log";
    String outFileName = "Sample_output.log";
    try (Stream<String> stream = Files.lines(Paths.get(inFileName))) {
        //stream.forEach(System.out::println);
        List<String> timeStamp = stream.flatMap(quoteRegex1::results)
                                    .map(r -> r.group(1))
                                    .collect(Collectors.toList());

        timeStamp.forEach(System.out::println);
        //Files.write(Paths.get(outFileName), dataSet);
    }
}

这个问题是从匹配模式和使用Java8 stream将流写入文件中的扩展

共有1个答案

梁盛
2023-03-14

您可以简单地连接流:

String inFileName = "Sample.log";
String outFileName = "Sample_output.log";
try (Stream<String> stream = Files.lines(Paths.get(inFileName))) {
    List<String> timeStamp = stream
        .flatMap(s -> Stream.concat(quoteRegex1.results(s),
                        Stream.concat(quoteRegex2.results(s), quoteRegex3.results(s))))
        .map(r -> r.group(1))
        .collect(Collectors.toList());

    timeStamp.forEach(System.out::println);
    //Files.write(Paths.get(outFileName), dataSet);
}

但是请注意,这将在每一行中执行三个单独的搜索,这不仅意味着性能较低,而且一行中匹配项的顺序不会反映它们的实际出现情况。这似乎不是你的模式的问题,但个别搜索甚至暗示可能的重叠匹配。

该链接答案的PatternStreamer还贪婪地将一个字符串的匹配项收集到ArrayList中,然后创建流。基于spliterator解决方案更好,如本答案中所示。

public final class MultiPatternSpliterator
extends Spliterators.AbstractSpliterator<MatchResult> {
    public static Stream<MatchResult> matches(String input, String... patterns) {
        return matches(input, Arrays.stream(patterns)
                .map(Pattern::compile).toArray(Pattern[]::new));
    }
    public static Stream<MatchResult> matches(String input, Pattern... patterns) {
        return StreamSupport.stream(new MultiPatternSpliterator(patterns,input), false);
    }
    private Pattern[] pattern;
    private String input;
    private int pos;
    private PriorityQueue<Matcher> pendingMatches;

    MultiPatternSpliterator(Pattern[] p, String inputString) {
        super(inputString.length(), ORDERED|NONNULL);
        pattern = p;
        input = inputString;
    }

    @Override
    public boolean tryAdvance(Consumer<? super MatchResult> action) {
        if(pendingMatches == null) {
            pendingMatches = new PriorityQueue<>(
                pattern.length, Comparator.comparingInt(MatchResult::start));
            for(Pattern p: pattern) {
                Matcher m = p.matcher(input);
                if(m.find()) pendingMatches.add(m);
            }
        }
        MatchResult mr = null;
        do {
            Matcher m = pendingMatches.poll();
            if(m == null) return false;
            if(m.start() >= pos) {
                mr = m.toMatchResult();
                pos = mr.end();
            }
            if(m.region(pos, m.regionEnd()).find()) pendingMatches.add(m);
        } while(mr == null);
        action.accept(mr);
        return true;
    }
}
Pattern[] p = Stream.of(reTimeStamp, reHostName, reServiceTime)
        .map(Pattern::compile)
        .toArray(Pattern[]::new);
try (Stream<String> stream = Files.lines(Paths.get(inFileName))) {
    List<String> timeStamp = stream
        .flatMap(s -> MultiPatternSpliterator.matches(s, p))
        .map(r -> r.group(1))
        .collect(Collectors.toList());

    timeStamp.forEach(System.out::println);
    //Files.write(Paths.get(outFileName), dataSet);
}

虽然重载的方法允许使用multipatternspliterator.matches(s,reTimeStamp,reHostName,reServiceTime)使用模式字符串创建流,但在flatmap操作中应该避免这种情况,因为该操作将为每一行输入重新编译每一个regex。这就是为什么上面的代码首先将所有模式编译成一个数组。这也是您的原始代码通过在流操作之外实例化PatternStreamer所做的事情。

 类似资料:
  • 问题内容: 我喜欢新的Java8 StreamAPI,并希望不仅将其用于一个文件。通常,我使用以下代码: 但是,如果可能的话,如何在一个流中读取两个文件呢? 问题答案: 没有任何额外的帮助程序功能或外部库,最简单的方法是: 如果尚未声明抛出受检查的异常,则可以 但是,a,我们不能这样做。有几种解决方法。一种是制作自己的版本,将其称为标准版本,然后将其作为捕获并重新抛出。另一种方法是使用抛出检查异常

  • 假设我有这样一个列表: 是否可以使用Java8流从该列表中每隔一秒获取一个元素以获得以下内容? 或者甚至每三个元素? 基本上,我正在寻找一个函数来获取流的每n个元素:

  • 问题内容: 我想一次从Python的文件/流中读取多个JSON对象。不幸的是刚刚s,至文件结束-; 似乎没有任何方法可以使用它来读取单个对象或延迟迭代这些对象。 有什么办法吗?使用标准库将是理想的选择,但是如果有第三方库,我会改用它。 目前,我将每个对象放在单独的行上并使用,但我真的不希望这样做。 使用范例 example.py in.txt 示例会话 问题答案: 这是一个非常简单的解决方案。秘诀

  • 可以接受一个目录列表,这些目录为Spring boot应用程序托管yaml文件。 但是列出的目录必须有名为application的文件。yml,否则它们不会被拾取。 如果我的应用程序允许用户使用任何名称放置yaml文件,那么我不能使用此选项。 然后,我手动将文件名添加到属性中,如下所示 spring.config.locationfile1.ymlfile2.yml 每次添加新文件时,我都必须修改

  • 我正在使用python,我有一个文件(

  • 问题内容: 我想知道如何从单个文件夹中读取多个文件(无需指定文件名,只是它们是json文件)。 另外,有可能将它们转换为DataFrame吗? 能给我一个基本的例子吗? 问题答案: 一种选择是使用os.listdir列出目录中的所有文件,然后仅查找以’.json’结尾的文件: 现在,您可以使用pandas DataFrame.from_dict将json(此时为python字典)读入pandas数