我正在使用我发现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 :) <a title="Hello :)"> Bye :( </a>';
=&GT;第二个:)
应该被忽略。
答案 0 :(得分:1)
首先预先过滤输入字符串。清理HTML标记中的任何表情符号:
$regex = '#<[^>]+('.implode('|', $regex).')[^>]+>#';
并运行上面的代码。
答案 1 :(得分: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] );
将它包裹在一个函数中,你很高兴。它可能比正则表达式更多的代码行,但它不是一个丑陋的,错误的维护噩梦(就像任何基于正则表达式的解决方案一样)。