假设我有一个很棒的想法,即为了探索互联网而制作一个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
答案 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”或链接的标签或其他组件,您就可以准确了解您拥有的链接数量,然后您可以逐个解析它们。它并不理想,因为它不接受正则表达式作为目标参数。