【问题标题】:Ignore matches from HTML tag defintions [duplicate]忽略来自 HTML 标记定义的匹配项 [重复]
【发布时间】:2012-05-22 16:55:47
【问题描述】:

我正在使用我找到的 here 的正则表达式替换一些文本。

$items = array(
  ':)'   => 'smile',
  ':('   => 'sad',
  '=))'  => 'laugh',
  ':p'   => 'tongue',      
); 

foreach($items as $key => $class)
  $regex[] = preg_quote($key, '#');

$regex = '#(?!<\w)('.implode('|', $regex).')(?!\w)#';

$string = preg_replace_callback($regex, function($matches) use($items){

  if(isset($items[$matches[0]])) 
    return '<span class="'.$items[$matches[0]].'">'.$matches[0].'</span>';

  return $matches[0];

}, $string);

它可以工作,但如何忽略 HTML 标签定义中的匹配项(如标签属性中)?

例如:

$string = 'Hello :) &lt;a title="Hello :)"&gt; Bye :( &lt;/a&gt;';

=> 第二个:) 应该被忽略。

【问题讨论】:

  • 简单的答案,就像每次涉及到 HTML 解析一样,是:不要使用正则表达式。
  • 但是 PHP 没有任何好的 HTML 解析器 :( 有 DOM 扩展,但让我们面对现实吧,它很烂..
  • @Alex 等等。呜???你认为DOMDocument?很烂,但你使用的是正则表达式?
  • @Alex 你决定使用正则表达式来解决问题。现在你有 2 个问题。
  • PHP DOMDocument 可以满足您的需求。 SearchStackOverflow 相关问题,或阅读文档。编辑:您说 DOMDocument 很烂,但是(尝试)使用 RegEx 来解决您的问题。对不起,我不能再帮你了。开发人员的好坏取决于他(或她)使用和理解的工具。

标签: php regex string


【解决方案1】:

这是一个基于 DOMDocument 的实现,它为您的 HTML 执行按书上的字符串替换:

$string = 'Hello :) <a title="Hello :)"> Bye :( </a>';

$items = array(
  ':)'   => 'smile',
  ':('   => 'sad',
  '=))'  => 'laugh',
  ':p'   => 'tongue',      
); 

foreach($items as $key => $class) $regex[] = preg_quote($key);

$regex = '#(?!<\w)('.implode('|', $regex).')(?!\w)#';

$doc = new DOMDocument();
$doc->loadHTML($string);

$xp = new DOMXPath($doc);

$text_nodes = $xp->query('//text()');

foreach ($text_nodes as $text_node)
{
  $parent  = $text_node->parentNode;
  $context = $text_node->nextSibling;
  $text    = $text_node->nodeValue;
  $matches = array();
  $offset  = 0;

  $parent->removeChild($text_node);

  while ( preg_match($regex, $text, $matches, PREG_OFFSET_CAPTURE, $offset) > 0 )
  {
    $match  = $matches[0];
    $smiley = $match[0];
    $pos    = $match[1];
    $prefix = substr($text, $offset, $pos - $offset);
    $offset = $pos + strlen($smiley);

    $span = $doc->createElement('span', $smiley);
    $span->setAttribute('class', $items[$smiley]);

    $parent->insertBefore( $doc->createTextNode($prefix), $context );
    $parent->insertBefore( $span, $context );
  }

  $suffix = substr($text, $offset);
  $parent->insertBefore( $doc->createTextNode($suffix), $context );
}

$body = $doc->getElementsByTagName('body');
$html = $doc->saveHTML( $body[0] );

将它包装在一个函数中,你就可以开始了。它可能比正则表达式更多的代码行,但它不是一个丑陋的、充满错误的维护噩梦(就像任何基于正则表达式的解决方案一样)。

【讨论】:

  • 谢谢,我会用 DOMDocument..
  • @Alex 我没有测试上面的代码。如果您发现了一些错误,请修正我的回答中的错误。
  • 我会的,但现在我正试图弄清楚如何使用 phpQuery 来做到这一点,phpQuery 是一个类似于 jquery 的 DOMdocument 接口。
  • @Alex 这不是一个坏主意。我没有想到phpQuery。
  • 该答案不涉及笑脸可能被评论或标签打断的情况,请参阅stackoverflow.com/questions/8193327/… - @Alex:对于 phpQuery,它也是基于 DOMDocument,因此您可以结合两个。
【解决方案2】:

首先预过滤您的输入字符串。清理 HTML 标记中的所有笑脸:

$regex = '#<[^>]+('.implode('|', $regex).')[^>]+>#';

然后在上面运行你的代码。

【讨论】:

    猜你喜欢
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 2016-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多