1

ここで見つけた正規表現を使用して、一部のテキストを置き換えています。

$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>';

=> 2 番目:)は無視する必要があります。

4

2 に答える 2

1

これは、HTMLの本ごとの文字列置換を行うDOMDocumentベースの実装です。

$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] );

関数でラップすれば、準備完了です。正規表現よりもコード行が多いかもしれませんが、(正規表現ベースのソリューションのように)醜い、バグの多いメンテナンスの悪夢ではありません。

于 2012-05-22T20:10:28.370 に答える
1

最初に入力文字列を事前にフィルタリングします。HTML タグ内のスマイリーをクリーンアップします。

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

上記のコードを実行します。

于 2012-05-22T17:28:02.957 に答える