Java - 如何测量匹配器处理

时间:2015-06-28 22:24:54

标签: java regex matcher

假设我有一个很棒的想法,即为了探索互联网而制作一个html链接标记解析器,我使用正则表达式来解析和捕获页面中每个链接的出现。此代码目前工作正常,但我正在寻求添加一些成员来反映"操作状态"。

public class LinkScanner {

    private static final Pattern hrefPattern = Pattern.compile("<a\\b[^>]*href=\"(.*?)\".*?>(.*?)</a>");

    public Collection<String> scan(String html) {
        ArrayList<String> links = new ArrayList<>();
        Matcher hrefMatcher = hrefPattern.matcher(html);
        while (hrefMatcher.find()) {
            String link = hrefMatcher.group(1);
            links.add(link);
        }
        return links;
    }
}

我如何衡量这个过程?

例如:认为这是一种假设的测量实现......

 public class LinkScannerWithStatus {

    private int matched;
    private int total;

    public Collection<String> scan(String html) {
        ArrayList<String> links = new ArrayList<>();
        Matcher hrefMatcher = hrefPattern.matcher(html);
        total = hrefMatcher.getFindCount(); // Assume getFindCount exists
        while (hrefMatcher.find()) {
            String link = hrefMatcher.group(1);
            links.add(link);
            matched++; // assume is a linear measurement mechanism
        }
        return links;
    }
}

我不知道从哪里开始..我甚至不知道连接&#34; Matcher处理&#34;在语法上有效:S

4 个答案:

答案 0 :(得分:2)

不幸的是Matcher没有用于衡量进度的侦听器界面。拥有一个可能会非常昂贵。

如果您将整页设为String个实例,则可以使用region选择页面区域。您可以使用它来按顺序扫描这些区域。然后,您可以向用户报告您当前正在扫描的部分。您可能需要回溯一下以允许区域重叠。

如果您使用hitEnd检查匹配是否正在进行回溯,则可以进行优化。如果它不是那么你就不需要回溯。

一个问题是网址的大小并没有真正受限,因此您需要选择您希望支持的网址大小。

如果你创建一个好的正则表达式,那么除非你正在处理真正庞大的文件,否则你不应该真的要报告进度。即使在这种情况下,I / O也应该比扫描HTML锚点有更多的开销。

答案 1 :(得分:2)

除了性能和内存问题之外,您可以使用DOM parser来评估HTML,这样,当您遍历DOM时,您可以执行给定的操作。

另一种可能性是将给定的HTML解释为XML并使用SAX。这是有效的,但假设一个结构可能不存在。

答案 2 :(得分:1)

根据Victor的要求,我会发布另一个答案。在这种情况下,CharSequence被实现为另一个CharSequence的包装器。当Matcher实例请求字符时,CountingCharSequence会向侦听器接口报告。

这样做有点危险,因为CharSequence.toString()方法返回一个无法监控的真实String实例。另一方面,似乎当前的实现实现起来相对简单并且确实有效。调用toString(),但似乎是在找到匹配项时填充组。最好在它周围编写一些单元测试。

哦,因为我必须手动打印“100%”标记,可能存在舍入错误或一个错误。快乐的调试:P

public class RegExProgress {

    // the org. LinkScanner provided by Victor
    public static class LinkScanner {
        private static final Pattern hrefPattern = Pattern.compile("<a\\b[^>]*href=\"(.*?)\".*?>(.*?)</a>");
        public Collection<String> scan(CharSequence html) {
            ArrayList<String> links = new ArrayList<>();
            Matcher hrefMatcher = hrefPattern.matcher(html);
            while (hrefMatcher.find()) {
                String link = hrefMatcher.group(1);
                links.add(link);
            }
            return links;
        }
    }

    interface ProgressListener {
        void listen(int characterOffset);
    }

    static class SyncedProgressListener implements ProgressListener {
        private final int size;
        private final double blockSize;
        private final double percentageOfBlock;

        private int block;

        public SyncedProgressListener(int max, int blocks) {
            this.size = max;
            this.blockSize = (double) size / (double) blocks - 0.000_001d;
            this.percentageOfBlock = (double) size / blockSize;

            this.block = 0;
            print();
        }

        public synchronized void listen(int characterOffset) {
            if (characterOffset >= blockSize * (block + 1)) {
                this.block = (int) ((double) characterOffset / blockSize);
                print();
            }
        }

        private void print() {
            System.out.printf("%d%%%n", (int) (block * percentageOfBlock));
        }
    }

    static class CountingCharSequence implements CharSequence {

        private final CharSequence wrapped;
        private final int start;
        private final int end;

        private ProgressListener progressListener;

        public CountingCharSequence(CharSequence wrapped, ProgressListener progressListener) {
            this.wrapped = wrapped;
            this.progressListener = progressListener;
            this.start = 0;
            this.end = wrapped.length();
        }

        public CountingCharSequence(CharSequence wrapped, int start, int end, ProgressListener pl) {
            this.wrapped = wrapped;
            this.progressListener = pl;
            this.start = start;
            this.end = end;
        }

        @Override
        public CharSequence subSequence(int start, int end) {
            // this may not be needed, as charAt() has to be called eventually
            System.out.printf("subSequence(%d, %d)%n", start, end);
            int newStart = this.start + start;
            int newEnd = this.start + end - start;
            progressListener.listen(newStart);
            return new CountingCharSequence(wrapped, newStart, newEnd, progressListener);
        }

        @Override
        public int length() {
            System.out.printf("length(): %d%n", end - start);
            return end - start;
        }

        @Override
        public char charAt(int index) {
            //System.out.printf("charAt(%d)%n", index);
            int realIndex = start + index;
            progressListener.listen(realIndex);
            return this.wrapped.charAt(realIndex);
        }

        @Override
        public String toString() {
            System.out.printf(" >>> toString() <<< %n", start, end);
            return wrapped.toString();
        }
    }

    public static void main(String[] args) throws Exception {
        LinkScanner scanner = new LinkScanner();
        String content = new String(Files.readAllBytes(Paths.get("regex - Java - How to measure a Matcher processing - Stack Overflow.htm")));
        SyncedProgressListener pl = new SyncedProgressListener(content.length(), 10);
        CountingCharSequence ccs = new CountingCharSequence(content, pl);
        Collection<String> urls = scanner.scan(ccs);
        // OK, I admit, this is because of an off-by one error
        System.out.printf("100%% - %d%n", urls.size());

    }
}

答案 3 :(得分:0)

因此,要测量您在文档中的进度,您希望找到匹配的总数,然后在匹配时匹配,您更新进度并将它们添加到存储的链接LinkedList。

您可以使用以下方式计算匹配总数: int countMatches = StringUtils.countMatches(String text,String target);

那么,只需查找字符串“href”或链接的标签或其他组件,您就可以准确了解您拥有的链接数量,然后您可以逐个解析它们。它并不理想,因为它不接受正则表达式作为目标参数。