Regex以剥离字符串中的外部HTML标记


Regex to strip outer HTML tags in string

我需要一个正则表达式来剥离字符串中的外部/顶级HTML标记,但保留内部标记。

$str = "<div>Start <br /> <span>test</span> end.</div>";

进入

$str = "Start <br /> <span>test</span> end.";

以及

$str = "<aside id="main" class="one">Start <br /> <span>test</span> end.</aside>";

进入

$str = "Start <br /> <span>test</span> end.";

preg_replace('/<[^>]*>/', '', $str);

删除所有标记,而不仅仅是外部标记。

请注意

使用正则表达式并不是修改HTML代码的最佳方式!在大多数情况下,使用DOMDocument或DOMDocumentFragement对象来修改或提取HTML代码中的数据会更好、更可靠。

然而,在一些有效的场景中,正则表达式更好,主要是当以下因素适用时:

  • 您知道您编辑的HTML代码将是有效的
  • 修改后的HTML结构在所有情况下都是相同的
  • 您只对代码进行了非常简单的更改
  • 性能很重要(例如,当它在循环中执行时)DOMDocument比简单的regex慢得多

代码

要从一些HTML代码中去除最外层的标记,请使用以下regex:

/* Note: 
 * The code must start with an opening tag and end with a closing tag. 
 * No white space or other text must be present before the first 
 * tag/after the last tag, else you get some unexpected results.
 */
$contents = preg_replace( '/^<[^>]+>|<'/[^>]+>$/', '', $markup );
            // ^<[^>]+>     This removes the first tag
            // <'/[^>]+>$   This removes the last closing tag

示例

此正则表达式适用于大多数HTML标记,例如

In: '<div class="my-text" id="text" style="color:red">some text</div>'
Out: 'some text' (expected result)

当第一个标签包含">"字符时,它会破坏一切,例如

In: '<div title="Home > Archives">Archive overview</div>'
Out: ' Archives">Archive overview' (unexpected result)

此外,开头或结尾的空白/文本将破坏正则表达式

In: '<div>Your name</div>:'
Out: 'Your name</div>:' (unexpected result)

当然,任何标签都将被剥离,没有任何健全性检查,例如

In: '<h2>Settings</h2><label>Page Title</label>'
Out: 'Settings</h2><label>Page Title' (unexpected result)

如何获取DOM元素,并模拟innerHTML()

$html = '<html><body><div><ul><li>1</li><li>2</li><li>3</li></ul></div></body></html>';
function DOMinnerHTML(DOMNode $element) { 
    $innerHTML = "";
    foreach ($element->childNodes as $child) { 
        $innerHTML .= $element->ownerDocument->saveHTML($child);
    }
    return $innerHTML; 
} 
$doc = new DOMDocument();
$doc->loadHTML($html);
foreach ($doc->getElementsByTagName('ul') as $child) {
    $html = DOMinnerHTML($child); 
    echo $html, PHP_EOL;
}

而不必求助于regexp

这个基本正则表达式可能会起作用。但是,它不考虑具有包含>s的属性的标签,因此会跳闸。

Find: <[^>]*>(['s'S]*)<'/[^>]*>
Replace: $1

如果您期望属性可能包含标记括号,则会变得更加复杂。

Find: <(?:[^>]*?(?:(?:"[^"]*?"|'[^']*?')+[^>]*?)|['s'S]*?)>(['s'S]*)<'/[^>]*>
Replace: $1

任何一个都应该做这个把戏。

我制作了一个函数,可以删除HTML标记及其内容:

功能:

<?php
function strip_tags_content($text, $tags = '', $invert = FALSE) {
  preg_match_all('/<(.+?)['s]*'/?['s]*>/si', trim($tags), $tags);
  $tags = array_unique($tags[1]);
  if(is_array($tags) AND count($tags) > 0) {
    if($invert == FALSE) {
      return preg_replace('@<(?!(?:'. implode('|', $tags) .')'b)('w+)'b.*?>.*?</'1>@si', '', $text);
    }
    else {
      return preg_replace('@<('. implode('|', $tags) .')'b.*?>.*?</'1>@si', '', $text);
    }
  }
  elseif($invert == FALSE) {
    return preg_replace('@<('w+)'b.*?>.*?</'1>@si', '', $text);
  }
  return $text;
}
?>

示例文本:$text='sample带标记的文本';

strip_tag($text)的结果:带有标签的示例文本

strip_tags_content($text)的结果:带有的文本

strip_tags_content($text,'')的结果:带有的示例文本

strip_tags_content的结果($text,'',TRUE);带有标签的文本

我希望有人有用:)