我需要使用Java从HTTP响应中删除一些内容。响应中的必填字段是:foo,bar和bla。我目前的模式很慢。任何想法如何改进?
响应:
...
<div class="ui-a">
<div class="ui-b">
<p><strong>foo</strong></p>
<p>bar</p>
</div>
<div class="ui-c">
<p><strong>bla</strong></p>
<p>...</p>
</div>
</div>
<div class="ui-a">
<div class="ui-b">
<p><strong>foo1</strong></p>
<p>bar1</p>
</div>
<div class="ui-c">
<p><strong>bla1</strong></p>
<p>...</p>
</div>
模式:
.*?<div class="ui-a">.*?<strong>(.*?)</strong>.*?<p>(.*?)</p>.*?</div>.*?<div class="ui-c">.*?<strong>(.*?)</strong>.*?
答案 0 :(得分:2)
由于您无法使用HTML解析器,请尝试以下操作:
import java.util.regex.*;
public class Main {
public static void main (String[] args) {
String html =
"...\n" +
"<div class=\"ui-a\">\n" +
"<div class=\"ui-b\">\n" +
" <p><strong>foo</strong></p>\n" +
" <p>bar</p>\n" +
"</div>\n" +
"<div class=\"ui-c\">\n" +
" <p><strong>bla</strong></p>\n" +
" <p>...</p>\n" +
"</div>\n" +
"</div>\n" +
"\n" +
"<div class=\"ui-a\">\n" +
"<div class=\"ui-b\">\n" +
" <p><strong>foo1</strong></p>\n" +
" <p>bar1</p>\n" +
"</div>\n" +
"<div class=\"ui-c\">\n" +
" <p><strong>bla1</strong></p>\n" +
" <p>...</p>\n" +
"</div>";
Pattern p = Pattern.compile(
"(?sx) # enable DOT-ALL and COMMENTS \n" +
"<div\\s+class=\"ui-a\"> # match '<div...ui-a...>' \n" +
"(?:(?!<strong>).)*+ # match everything up to <strong> \n" +
"<strong>([^<>]++)</strong> # match <strong>...</strong> \n" +
"(?:(?!<p>).)*+ # match up to <p> \n" +
"<p>([^<>]++)</p> # match <p>...</p> \n" +
"(?:(?!<div\\s+class=\"ui-c\">).)*+ # match up to '<div...ui-a...>' \n" +
"<div\\s+class=\"ui-c\"> # match '<div...ui-c...>' \n" +
"(?:(?!<strong>).)*+ # match everything up to <strong> \n" +
"<strong>([^<>]++)</strong> # match <strong>...</strong> \n"
);
Matcher m = p.matcher(html);
while(m.find()) {
System.out.println("---------------");
for(int i = 1; i <= m.groupCount(); i++) {
System.out.printf("group(%d) = %s\n", i, m.group(i));
}
}
}
}
将打印以下内容到控制台:
--------------- group(1) = foo group(2) = bar group(3) = bla --------------- group(1) = foo1 group(2) = bar1 group(3) = bla1
请注意我的更改:
*+
和++
:http://www.regular-expressions.info/possessive.html .*?
,我使用了(?:(?!...).)*+
。第一个,.*?
将跟踪所有可能的匹配,以便能够在稍后阶段进行回溯。后者(?:(?!...).)*+
不会跟踪这些匹配。这应该更快(不确定多少......)。
答案 1 :(得分:1)
似乎,你要找的只是标签之间,你可以使用:
<strong>([a-zA-Z0-9]+)</strong>
此外,根据强标记内的内容,您可以更改模式,例如如果您确定文本总是小的情况下您可以从上面的模式中删除A-Z,或者如果它只包含4个字符,您可以在模式后使用{4}。
答案 2 :(得分:0)
将所有字符串转换为<p>
标记,以便您可以搜索其中包含的内容(并删除<strong>
)。
但如果你使用解析器而不是正则表达式可能会更好。 Search all <p>; If <p> has childNode then get <p>.text; else get <p>.text.
答案 3 :(得分:0)
请考虑使用JSoup。有些well-known problems使用正则表达式来解析HTML。
答案 4 :(得分:0)
如果您不依赖正则表达式来验证html,并且您没有权限修改html的结构。此外,摆脱最后的.*?
是必要的,因为第一个将在后续比赛中发生冲突。基本上你有.*?.*?
因为引擎会尝试查找最后<strong>
标记和下一个<div class="ui-a">
标记之间所有字符的所有可能排列。非常低效。试试这个:
.*?<div class="ui-a">.*?<strong>(.*?)</strong>.*?<p>(.*?)</p>.*?</div>.*?<div class="ui-c">.*?<strong>(.*?)</strong>
旁注:您确定要在<strong>
内找到第一个<div class="ui-a">
标记,因为第一个<strong>
标记似乎发生在<div class="ui-b">
内案例:
.*?<div class="ui-b">.*?<strong>(.*?)</strong>.*?<p>(.*?)</p>.*?</div>.*?<div class="ui-c">.*?<strong>(.*?)</strong>
更准确。
如果您知道所需的捕获组中没有嵌套标记,则可以使用以下方法进一步优化:
.*?<div class="ui-b">.*?<strong>([^<]*)</strong>.*?<p>([^<]*)</p>.*?</div>.*?<div class="ui-c">.*?<strong>([^<]*)</strong>
答案 5 :(得分:0)
你的正则表达式既有领导也有训练。*?我不明白为什么。如果数据格式良好,你只是意味着一定数量的空白,是吗?为什么不是:
Pattern p = "<div class=\"ui-b\">\s*<p><strong>([^<]*)</strong></p>\s*<p>([^<]*)</p>\s*</div>\s*<div class=\"ui-c\">\s*<p><strong>([^<]*)</strong></p>";
Matcher m = p.matcher(responseText);
while (m.find()) {
String foo = m.group(1);
String bar = m.group(2);
String bla = m.group(3);
/* do whatever w/ foo, bar, bla */
}
我放弃了所有.*?
并用空格替换内部的那些(或者在那里你可以省略更多 - 也许)。但无论如何,为什么你需要开始和结束。*?
如果格式良好,只需进行空格搜索就可以大幅增加。