用于破坏HTML匹配的正则表达式

时间:2017-12-27 15:05:48

标签: php regex

我想删除损坏的HTML标记,例如:

<p>right here</p>....<iframe class
<b>Very nice</b>...<ifr

等。我的其余部分将内容限制放在HTML字符串上并关闭任何打开的标记工作正常,这个破碎的标记将始终位于字符串的 end 。 到目前为止我实现的是:

#<[^>]*#i

问题在于它也考虑了<iframe标记的<iframe>部分。

iframe仅举例......

编辑: 我的PHP版本不支持DOMDocument,这就是为什么要使用regEx。我已经实现Closing open HTML tags来关闭字符串中的任何打开标签,但它允许使用损坏的标签。

2 个答案:

答案 0 :(得分:1)

您需要使用任何HTML解析器来获得正确的结果,但这是使用正则表达式的方法,

(<\w+(?:\s+\w+=\"[^"]+\")*)(?=[^>]+(?:<|$))

demo and some explanation

使用

$res = preg_replace('/(<\w+(?:\s+\w+=\"[^"]+\")*)(?=[^>]+(?:<|$))/, '$1>', $str);

答案 1 :(得分:0)

使用标准PHP扩展始终是最佳选择。但是对于那些遇到同样问题并受PHP版本限制的人来说,这个功能可以完全限制任何HTML字符串的长度限制:

/**
 * Crops HTML text ensuring valid HTML
 * 
 * @param string    HTML string
 * @param int       The length up to which HTML string is to be limited
 */
protected function limitHtml($html, $length)
{
  // Ignoring style tags for displayable string length
  preg_match_all('/<style>(.*?)<\/style>/s', $html, $cssMatches);
  $html = preg_replace('/<style>(.*?)<\/style>/s', '', $html);
  // css
  $css = '';
  if ( isset($cssMatches[1]) ) {
    foreach ( $cssMatches[1] as $cmatch ) {
      $css .= "<style>$cmatch</style>";
    }
  }      
  $truncatedText = substr($html, 0, $length);
  $pos = strpos($truncatedText, ">");
  if($pos !== false)
  {
      $html = substr($html, 0,$length + $pos + 1);
  }
  else
  {
      $html = substr($html, 0,$length);
  }

  // Relace The Broken Opened Tag From The the end of String
  $lastCorruptopnArrow = strrpos($html, "<");
  $lastCloseArrow = strrpos($html, ">");
  if ( $lastCloseArrow < $lastCorruptopnArrow ) {
    $corruptHTmlString = substr($html, $lastCorruptopnArrow, strlen($html) - $lastCorruptopnArrow);
    $html = preg_replace('/'. preg_quote($corruptHTmlString, '/') . '$/', '', $html);
  }

  preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result);

  $openedtags = $result[1];
  preg_match_all('#</([a-z]+)>#iU', $html, $result);
  $closedtags = $result[1];
  $len_opened = count($openedtags);
  if (count($closedtags) == $len_opened)
  {
      return $css . $html;
  }
  $openedtags = array_reverse($openedtags);
  for ($i=0; $i < $len_opened; $i++)
  {
      if (!in_array($openedtags[$i], $closedtags))
      {
          $html .= '</'.$openedtags[$i].'>';
      }
      else
      {
          unset($closedtags[array_search($openedtags[$i], $closedtags)]);
      }
  }
  return $css . $html;
}  

在我的情况下完美地工作。打开以增强:limit_html()