Поиск тегов без атрибутов в HTML с помощью регулярных выражений

245
15 декабря 2016, 16:23

Стоит задача поиска всех не повторяющихся тегов без атрибутов (например, head, body) в HTML файле с помощью регулярных выражений.

public static void main(String[] args) throws FileNotFoundException {
    String tmp = fileReader(fileName); //метод читает весь файл и возвращает строку, в которой мы ищем наши теги
    Pattern p = Pattern.compile("<[^> ]+>");
    Matcher m = p.matcher(tmp);
    while (m.find()) {
        System.out.println(m.group());
    }
}

Данный код выводит все теги без атрибутов, а мне нужны только те, которые не повторяются.

Я пробовал так: ("<[^> ]+>")?. ? означает, что оно будет искать совпадения, которые повторяются 0 или 1 раз. Не работает.

Как это можно сделать?

Answer 1

Вы не сможете решить эту задачу чистыми регулярками в Java - в движке регулярок этого языка отсутствуют обратные позиционные проверки непостоянной длины, то бишь:

(?<![a-z].*)

Вы можете посмотреть как примерно могло бы выглядеть такое регулярное выражение:
https://regex101.com/r/iH6gR5/1

<(\w+)>(?=.*?(<\/\1>))(?!.*<\1)

Его проблема в том, что оно совпадает с последним DIV, так как справа от него нет другого DIV.

У меня нет .NET для тестирования регулярки (в нем есть ?<!.*), но рабочий вариант должен выглядеть примерно так:

<(\w+)>(?<!<\1>.*<\1>)(?=.*?(<\/\1>))(?!.*<\1)

P.S. Регулярное выражение не учитывает комментарии, блоки CDATA и прочие прелести синтаксиса HTML, если добавить поддержку этого, то регулярка будет настолько сложной, что не принесет образовательного эффекта.

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

String tmp = "<html><head></head><body><div></div><DIV><pre></pre></div></body></html>";
Pattern p = Pattern.compile( "<([^> ]+)>(?=(?:.*<(\\1)>)?)", Pattern.DOTALL|Pattern.CASE_INSENSITIVE );
Matcher m = p.matcher(tmp);
List<String> exclude = new ArrayList<String>();
while ( m.find() ) {
    if ( m.group(2) != null ) {
        exclude.add( m.group(2).toLowerCase() );
    }
    if ( exclude.indexOf( m.group(1).toLowerCase() ) == -1 ) {
        System.out.println( m.group() );
    }
}

Результат:

<html>
<head>
</head>
<body>
<pre>
</pre>
</body>
</html>

Были исключены div, так как они повторяются.

READ ALSO
Видео на всю ширину страницы в Adobe Muse

Видео на всю ширину страницы в Adobe Muse

Доброго времени сутокЯ столкнулся с такой проблемой: не могу растянуть видео на всю ширину страницы в Adobe Muse

393
Uncaught SyntaxError: Unexpected token o &amp; b

Uncaught SyntaxError: Unexpected token o & b

В инструментах разработчика Chrome 4 ошибки:

255
Заголовок по ширине картинки

Заголовок по ширине картинки

Есть горизонтальный список, состоящий из картинок и заголовков под нимиХочу сделать, чтобы заголовок зависел от ширины картинки

315
border-botton у div сверху

border-botton у div сверху

Вот смотрите, http://jsfiddlenet/mgpv8qvt/1/ почему подчеркивание идет над строкой а не под?

344