Почему Regex Java выдает исключение stackru иногда?
Я пытаюсь сделать регулярное выражение для тегов 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-адрес), и он выдал ошибку, а затем снова протестировал ее, и она работала хорошо.
2 ответа
Я думаю, что 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]*? )
)
)
)
>
Основываясь на ваших входных данных я проверил, и он работает нормально, я не могу воспроизвести ошибку, вот реализация:
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
String htmlScript = downloadWebPage("https://stackru.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();
}
Вот вывод: https://pastebin.com/s9DbBVBJ