Почему 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

Другие вопросы по тегам