Во-первых, обратите внимание, что пустые элементы HTML по определению не являются вложенными.
Обновление: В приведенном ниже решении рекурсивно применяется регулярное выражение пустого элемента для удаления "nested-empty-element" структур, таких как: <p><strong></strong></p>
(с учетом оговорок, указанных ниже ).
Простая версия:
Это работает довольно хорошо (см. Предостережения ниже) для HTML, не имеющего атрибутов начального тега, содержащего <>
забавные вещи, в виде (непроверенного) фрагмента VB.NET:
Dim RegexObj As New Regex("<(\w+)\b[^>]*>\s*</\1\s*>")
Do While RegexObj.IsMatch(html)
html = RegexObj.Replace(html, "")
Loop
Улучшенная версия
<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[\w\-.:]+))?)*\s*/?>\s*</\1\s*>
Вот расширенная версия без комментариев в VB.NET (не проверена):
Dim RegexObj As New Regex("<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:""[^""]*""|'[^']*'|[\w\-.:]+))?)*\s*/?>\s*</\1\s*>")
Do While RegexObj.IsMatch(html)
html = RegexObj.Replace(html, "")
Loop
Это более сложное регулярное выражение правильно соответствует действительному пустому элементу HTML 4.01 , даже если у него есть угловые скобки в значениях его атрибута (еще раз, учитывая предостережения ниже). Другими словами, это регулярное выражение правильно обрабатывает все значения атрибутов начального тега, которые заключены в кавычки (которые могут иметь <>
), не заключены в кавычки (что не может) и пустые. Вот полностью прокомментированная (и протестированная) версия PHP:
function strip_empty_tags($text) {
// Match empty elements (attribute values may have angle brackets).
$re = '%
# Regex to match an empty HTML 4.01 Transitional element.
< # Opening tag opening "<" delimiter.
(\w+)\b # $1 Tag name.
(?: # Non-capture group for optional attribute(s).
\s+ # Attributes must be separated by whitespace.
[\w\-.:]+ # Attribute name is required for attr=value pair.
(?: # Non-capture group for optional attribute value.
\s*=\s* # Name and value separated by "=" and optional ws.
(?: # Non-capture group for attrib value alternatives.
"[^"]*" # Double quoted string.
| \'[^\']*\' # Single quoted string.
| [\w\-.:]+ # Non-quoted attrib value can be A-Z0-9-._:
) # End of attribute value alternatives.
)? # Attribute value is optional.
)* # Allow zero or more attribute=value pairs
\s* # Whitespace is allowed before closing delimiter.
> # Opening tag closing ">" delimiter.
\s* # Content is zero or more whitespace.
</\1\s*> # Element closing tag.
%x';
while (preg_match($re, $text)) {
// Recursively remove innermost empty elements.
$text = preg_replace($re, '', $text);
}
}
Предостережения: Эта функция не анализирует HTML. Он просто сопоставляет и удаляет любую последовательность текстового шаблона, соответствующую действительному пустому элементу HTML 4.01 (который по определению является вложенным , а не ). Обратите внимание, что это также ошибочно сопоставляет и удаляет тот же текстовый шаблон, который может встречаться вне обычной разметки HTML, например, внутри тегов SCRIPT и STYLE, комментариев HTML и атрибутов других начальных тегов. Это регулярное выражение не работает с короткими тегами. Любой поклонник bobenc, желающий дать этому ответу автоматический нисходящий голос, покажите мне один действительный пустой элемент HTML 4.01, которому это регулярное выражение не удается правильно сопоставить. Это регулярное выражение следует спецификации W3C и действительно работает.
Обновление: Это решение для регулярных выражений также не работает (и ошибочно удалит допустимую разметку), если вы сделаете что-то невероятно маловероятно (но совершенно верно), например:
<div att="<p att='">stuff</div><div att="'></p>'">stuff</div>
Резюме:
Если подумать, просто используйте анализатор HTML!