【问题标题】:Streaming Pattern Matching using Regex使用正则表达式进行流模式匹配
【发布时间】:2016-04-20 02:07:46
【问题描述】:

我想解析一个以 Warc 0.9 版格式化的大文本文件。此类文本的示例是here。如果您看一下,您会发现整个文档由以下条目列表组成。

[Warc Headers]

[HTTP Headers]

[HTML Content]

我需要从每个条目中提取 URL 和 HTML 内容(请注意,示例文件由 多个 页面条目组成,每个条目的格式都与上面的内容类似。)

我在 Java 中使用了以下正则表达式:

Pattern.compile("warc/0\\.9\\s\\d+\\sresponse\\s(\\S+)\\s.*\n\n.*\n\n(.*)\n\n", Pattern.DOTALL)

其中组 1 和组 2 分别代表 URL 和 HTML 内容。这段代码有两个问题:

  1. 找到匹配项非常慢。
  2. 仅与首页匹配。

Java 代码:

if(mStreamScanner.findWithinHorizon(PAGE_ENTRY, 0) == null){
    return null;
} else {
    MatchResult result = mStreamScanner.match();
    return new WarcPageEntry(result.group(1), result.group(2));
}

问题:

  • 为什么我的代码只解析第一页条目?
  • 是否有更快的方法以流方式解析大文本?

【问题讨论】:

  • .* 更改为.*? 可能会提高性能,因为它会减少回溯,甚至可能更适合您的使用。
  • @Andreas 谢谢,现在速度更快了,但只提取了前两个条目。
  • 你考虑过使用 HTML 解析器吗?
  • @anubhava 是的,我正在使用 Jsoup。

标签: java regex warc


【解决方案1】:

我不会用正则表达式处理这些巨大的 HTML 字符串。改用文档的结构怎么样?

例如像这样:

HashMap<String, String> output = new HashMap<>();
Pattern pattern = Pattern.compile("^warc\\/0\\.9\\s\\d+\\sresponse\\s(\\S+)\\s.*");

try (InputStreamReader is = new InputStreamReader(new FileInputStream("excerpt.txt"), "UTF-8")) {               
    try (BufferedReader br = new BufferedReader(is)) {      
        String line;        
        while ((line = br.readLine()) != null) {
            Matcher matcher = pattern.matcher(line);

            if (matcher.matches()) {
                entityLoop: while (true) {
                    String url = matcher.group(1);

                    // skip header
                    int countEmptyLines = 0;
                    while ((line = br.readLine()) != null) {
                        if ("".equals(line)) {
                            countEmptyLines++;
                            if (countEmptyLines == 2) break;
                        }
                    }

                    // extract HTML
                    StringBuilder sb = new StringBuilder();
                    while ((line = br.readLine()) != null) {
                        matcher = pattern.matcher(line);
                        if (matcher.matches()) { 
                            // got all HTML; store our findings
                            output.put(url, sb.toString());
                            continue entityLoop; 
                        }
                        sb.append(line);
                    }
                    break; // no more url/html-entities available
                }
            }
        }
    }       
} catch (IOException e) {
    // do something smart
}

// now all your extracted data is stored in "output"

上面的代码还有改进的空间。但它应该让您了解如何开始。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多