Отрицание регулярного выражения для поиска HTML-тегов и их содержимого - Java - PullRequest
2 голосов
/ 15 мая 2019

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

Ввод тела:

<h1>This is heading 1</h1>
<h2 style="color: aqua">This is heading 2</h2>
<h3>This is heading 3</h3>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<a href="https://www.w3schools.com">This is a link</a>
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>

Я получил список разрешенных тегов, и мне нужно удалить также все остальные теги с их содержимым.например {h3, p, ul}

Сначала я удаляю все параметры (они не разрешены), затем я придумал это регулярное выражение, которое удаляет теги и контент.

String regex = "(?i)<([h3|ul|p]+)>\\n?.*\\n?<\\/\\1>";

Это работает, но теперьЯ должен отрицать это и удалить все теги и контент, кроме тех, которые приведены в ...

Я пробовал это, но не работает:

`...[?!h3|ul|p]...`

Желаемый результат для этого примера:

<h3>This is heading 3</h3>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<ul>
</ul>

Не совсем понимаю Negative Lookahead и как применить его к моей проблеме, поэтому буду благодарен за любой совет.

Ответы [ 2 ]

1 голос
/ 15 мая 2019

Отрицательный взгляд, который вы пытаетесь использовать, должен быть записан как (?!(?:h3|ul|p)\b), который не выберет тег h3, ul или p.Обратите внимание на использование границы слова \b после него, чтобы отклонить точное совпадение этих тегов.И помимо удаления этих тегов, вам также придется удалить пробелы, оставшиеся после удаления этих тегов, следовательно, в целом, регулярное выражение, которое вам нужно использовать, это,

\h*<(?!(?:h3|ul|p)\b)([^>]+).*?>[\w\W]*?</\1>\s*

Regex Объяснение:

  • \h* - Сопоставляет ноль или более горизонтальных пробелов (пробел и табуляции и, возможно, другие, которые существуют) перед тегом
  • < - Начало тега
  • (?!(?:h3|ul|p)\b) - Отрицательный взгляд на точное отклонение тегов h3 ul и p
  • ([^>]+) - Соответствует имени тега одному или нескольким символам и захватывает в group1 для обратной ссылки на него позже.Вы можете использовать что-то вроде \w+ или набор символов с разрешенными символами, чтобы соответствовать только тому, что вы хотите.
  • .*?> - При желании соответствовать нулю или большему количеству символов (в основном, атрибутам) с последующим закрытием начального тега с помощью >
  • [\w\W]*? - Соответствует любому символу ноль или более, включая символы новой строки не жадным способом
  • </\1> - Соответствует закрытию тега, где \1 представляет то, что ранее соответствовало тегуname
  • \s* - соответствует нулю или более пробелов, которые в основном занимают пустое пространство, созданное удалением тегов

Regex Demo

Демонстрационный код Java,

String s = "<h1>This is heading 1</h1>\r\n" + 
        "<h2 style=\"color: aqua\">This is heading 2</h2>\r\n" + 
        "<h3>This is heading 3</h3>\r\n" + 
        "<p>This is a paragraph.</p>\r\n" + 
        "<p>This is another paragraph.</p>\r\n" + 
        "<a href=\"https://www.w3schools.com\">This is a link</a>\r\n" + 
        "<ul>\r\n" + 
        "  <li>Coffee</li>\r\n" + 
        "  <li>Tea</li>\r\n" + 
        "  <li>Milk</li>\r\n" + 
        "</ul>";

System.out.println("Before:\n" + s);
System.out.println("\nAfter:\n" + s.replaceAll("\\h*<(?!(?:h3|ul|p)\\b)([^>]+).*?>[\\w\\W]*?</\\1>\\s*", ""));

Вывод,

Before:
<h1>This is heading 1</h1>
<h2 style="color: aqua">This is heading 2</h2>
<h3>This is heading 3</h3>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<a href="https://www.w3schools.com">This is a link</a>
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>

After:
<h3>This is heading 3</h3>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<ul>
</ul>
1 голос
/ 15 мая 2019

Возможно, вы захотите извлечь те, которые вы хотите, чтобы быть в желаемом выводе. Это выражение может быть лучшим выбором для этого, и его можно изменить, если вы хотите:

(<(p|h3.*)>.*<\/(.*)>)|(<(ul.*)>[\s\S]*<\/(ul)>)

У него есть две группы, одна для p и h3, а другая для ul, которую можно объединить в другую группу захвата:

((<(p|h3.*)>.*<\/(.*)>)|(<(ul.*)>[\s\S]*<\/(ul)>))

RegEx

Если это не было вашим желаемым выражением, вы можете изменить / изменить выражение в regex101.com .

enter image description here

RegEx Circuit

Вы также можете визуализировать свои выражения в jex.im :

enter image description here

Java-тестирование

import java.util.regex.Matcher;
import java.util.regex.Pattern;

final String regex = "((<(p|h3.*)>.*<\\/(.*)>)|(<(ul.*)>[\\s\\S]*<\\/(ul)>))";
final String string = "<h1>This is heading 1</h1>\n"
     + "<h2 style=\"color: aqua\">This is heading 2</h2>\n"
     + "<h3>This is heading 3</h3>\n"
     + "<p>This is a paragraph.</p>\n"
     + "<p>This is another paragraph.</p>\n"
     + "<a href=\"https://www.w3schools.com\">This is a link</a>\n"
     + "<ul>\n"
     + "  <li>Coffee</li>\n"
     + "  <li>Tea</li>\n"
     + "  <li>Milk</li>\n"
     + "</ul>";

final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);

while (matcher.find()) {
    System.out.println("Full match: " + matcher.group(0));
    for (int i = 1; i <= matcher.groupCount(); i++) {
        System.out.println("Group " + i + ": " + matcher.group(i));
    }
}

JavaScript Demo

const regex = /((<(p|h3.*)>.*<\/(.*)>)|(<(ul.*)>[\s\S]*<\/(ul)>))/gm;
const str = `<h1>This is heading 1</h1>
<h2 style="color: aqua">This is heading 2</h2>
<h3>This is heading 3</h3>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<a href="https://www.w3schools.com">This is a link</a>
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

Это выражение может захватывать только желаемый результат. Он не следует стратегии отрицания.

...