Оптимизация паттернов - PullRequest
3 голосов
/ 11 ноября 2011

Мне нужно очистить некоторый контент из HTTP-ответа с помощью Java. Обязательные поля в ответе: 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>.*?

Ответы [ 6 ]

2 голосов
/ 11 ноября 2011

Поскольку вы не можете использовать анализатор 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 / ownive.html
  • вместо .*?, я использовал (?:(?!...).)*+. Первый, .*? будет отслеживать все возможные совпадения, которые он может сделать, чтобы иметь возможность вернуться на более поздний этап. Последний, (?:(?!...).)*+, не будет отслеживать эти матчи.

Это должно сделать это быстрее (не уверен, насколько ...).

1 голос
/ 11 ноября 2011

Кажется, что вы ищете только между тегами, вы можете работать с:

<strong>([a-zA-Z0-9]+)</strong>

дальше, в зависимости от того, что находится внутри сильного тега, вы можете изменить шаблон, например, если вы уверены, чтотекст всегда маленький, вы можете удалить AZ из шаблона выше или, если он содержит только 4 символа, вы можете использовать {4} после шаблона.

0 голосов
/ 11 ноября 2011

Ваше регулярное выражение имеет как ведущие, так и обучение. *? Я не понимаю почему. И если данные хорошо отформатированы, вы действительно имеете в виду определенное количество пробелов, да? Почему бы не быть:

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 */
}

Где я бросил все твои .*?

и заменил внутренние пробелами (или есть что-то еще, что вы, например, опускаете - возможно). Но независимо от того, зачем вам нужно начало и конец. *?

Если он хорошо отформатирован, просто выполняйте поиск пробелов, это должно значительно увеличить его.

0 голосов
/ 11 ноября 2011

Если вы не полагаетесь на регулярное выражение для проверки 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>
0 голосов
/ 11 ноября 2011

Попробуйте вместо этого использовать JSoup .Есть известные проблемы с использованием регулярных выражений для разбора HTML.

0 голосов
/ 11 ноября 2011

Все ваши строки в теге <p>, так что вы можете искать его содержимое (и удалять <strong>). Но может быть лучше, если вы используете парсер, а не регулярное выражение. Search all <p>; If <p> has childNode then get <p>.text; else get <p>.text.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...