我正在尝试为HTML标记创建正则表达式。
到目前为止,我创建的正则表达式是<(/?)(\w+?)(\s(.*?))*?((/>)|>)
,当我在线测试时,它完美地工作;但是当我使用Java正则表达式对它进行测试时,它有时会抛出StackOverFlowError,有时却不会抛出它。
我正在使用此代码进行测试:
public static void parseHtml(String urlString){
new Thread(new Runnable() {
@Override
public void run() {
int count = 0;
int count2 = 0;
String htmlScript = downloadWebPage(urlString);
Matcher matcher = Pattern.compile("<(/?)(\\w+?)(\\s(.*?))*?((/>)|>)",
Pattern.DOTALL).matcher(htmlScript);
while(matcher.find()) {
System.out.println(matcher.group());
}
}
}).start();
}
所以,我的问题是: 为什么Java的正则表达式引擎有时会抛出StackOverFlowError,有时它不会抛出?
注意:我使用相同的测试输入(相同的URL),它抛出错误,稍后再次测试它,它运行良好。
答案 0 :(得分:0)
我认为Java在某些情况下非常不喜欢轮换 哪里有潜在的回溯问题。
因此,此部分(\s(.*?))*?
会在回溯中造成撤消负担
机制。
( # (3 start)
\s
( .*? ) # (4)
)*? # (3 end)
最终结果是嵌套的可选量词
它可以减少到([\S\s]*?)
而不会出现嵌套问题。
此外,此部分((/>)|>)
可以缩减为(/?>)
,无需使用
通过交替换另一个堆栈帧。
总的来说,你并不真正需要捕获组。
如果你只需要解析标签,这是html的初始级别 解析,然后使用正则表达式是好的。
如果您想要解析单个标记,则需要DOM解析器。
我发现这个正则表达式将解析所有单独的html / xml标签。
https://regex101.com/r/YXhCxe/1
"<(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\\s+(?>\"[\\S\\s]*?\"|'[\\S\\s]*?'|(?:(?!/>)[^>])?)+)?\\s*>)[\\S\\s]*?</\\1\\s*(?=>))|(?:/?[\\w:]+\\s*/?)|(?:[\\w:]+\\s+(?:\"[\\S\\s]*?\"|'[\\S\\s]*?'|[^>]?)+\\s*/?)|\\?[\\S\\s]*?\\?|(?:!(?:(?:DOCTYPE[\\S\\s]*?)|(?:\\[CDATA\\[[\\S\\s]*?\\]\\])|(?:--[\\S\\s]*?--)|(?:ATTLIST[\\S\\s]*?)|(?:ENTITY[\\S\\s]*?)|(?:ELEMENT[\\S\\s]*?))))>"
扩展
<
(?:
(?:
(?:
# Invisible content; end tag req'd
( # (1 start)
script
| style
| object
| embed
| applet
| noframes
| noscript
| noembed
) # (1 end)
(?:
\s+
(?>
" [\S\s]*? "
| ' [\S\s]*? '
| (?:
(?! /> )
[^>]
)?
)+
)?
\s* >
)
[\S\s]*? </ \1 \s*
(?= > )
)
| (?: /? [\w:]+ \s* /? )
| (?:
[\w:]+
\s+
(?:
" [\S\s]*? "
| ' [\S\s]*? '
| [^>]?
)+
\s* /?
)
| \? [\S\s]*? \?
| (?:
!
(?:
(?: DOCTYPE [\S\s]*? )
| (?: \[CDATA\[ [\S\s]*? \]\] )
| (?: -- [\S\s]*? -- )
| (?: ATTLIST [\S\s]*? )
| (?: ENTITY [\S\s]*? )
| (?: ELEMENT [\S\s]*? )
)
)
)
>
答案 1 :(得分:-1)
在我输入的基础上我测试过它工作正常,我无法重现错误,这里是实现:
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
String htmlScript = downloadWebPage("https://stackoverflow.com/questions/13684468/java-runnable-run-method-returning-a-value");
Matcher matcher = Pattern.compile("<(/?)(\\w+?)(\\s(.*?))*?((/>)|>)",
Pattern.DOTALL).matcher(htmlScript);
while(matcher.find()) {
System.out.println(matcher.group());
}
}
}).start();
}
private static String downloadWebPage(String urlString) {
StringBuilder sb = new StringBuilder();
try {
URL u = new URL(urlString);
BufferedReader in = new BufferedReader(new InputStreamReader(u.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
sb.append(inputLine);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}