PHP Token заменяет HTML-объекты - PullRequest
1 голос
/ 15 сентября 2011

Я хочу сделать определенные слова / строки похожими на ссылки, если они найдены в тексте.У меня есть фрагмент кода из php.bet, который делает это, но он также удаляет начало и конец тегов из <a href="http://www.domain.com/index.php" title="Home">go to homepage</a>.Вы можете помочь решить эту проблему?

Вот фрагмент кода:

<?php

$str_in =   '<p>Hi there worm! You have a disease!</p><a href="http://www.domain.com/index.php" title="Home">go to homepage</a>';
$replaces=      array(
                'worm' => 'http://www.domain.com/index.php/worm.html',
                'disease' => 'http://www.domain.com/index.php/disease.html'
                );

function addLinks($str_in, $replaces)
{
  $str_out = '';
  $tok = strtok($str_in, '<>');
  $must_replace = (substr($str_in, 0, 1) !== '<');
  while ($tok !== false) {
    if ($must_replace) {
      foreach ($replaces as $tag => $href) {
        if (preg_match('/\b' . $tag . '\b/i', $tok)) {
          $tok = preg_replace(
                                '/\b(' . $tag . ')\b/i',
                                '<a title="' . $tag . '" href="' . $href . '">\1</a>',
                                $tok,
                                1);
          unset($replaces[$tag]);
        }
      }
    } else {
      $tok = "<$tok>";
    }
    $str_out .= $tok;
    $tok = strtok('<>');
    $must_replace = !$must_replace;
  }
  return $str_out;
}

echo addLinks($str_in, $replaces);

Результат:

Привет, червь!У вас есть болезнь!

a href = "http://www.domain.com/index.php" title =" Home "/ a

Слова" червь "и" болезнь "преобразуются в ссылки по желанию,но остальное ...

Спасибо большое!

Ответы [ 2 ]

1 голос
/ 16 сентября 2011

Эта пара функций должна делать то, что вы хотите без проблем, которые возникают при разборе HTML с регулярным выражением или str_replace.

function process($node, $replaceRules)
{
    if($node->hasChildNodes()) {
        $nodes = array();
        foreach ($node->childNodes as $childNode) {
            $nodes[] = $childNode;
        }
        foreach ($nodes as $childNode) {
            if ($childNode instanceof DOMText) {
                $text = preg_replace(
                    array_keys($replaceRules),
                    array_values($replaceRules),
                    $childNode->wholeText);
                $node->replaceChild(new DOMText($text),$childNode);
            }
            else {
                process($childNode, $replaceRules);
            }
        }
    }
}

function addLinks($str_in, $replaces)
{
    $replaceRules = array();    
    foreach($replaces as $k=>$v) {
        $k = '/\b(' . $k . ')\b/i';
        $v = '<a href="' . $v . '">$1</a>';
        $replaceRules[$k] = $v;
    }

    $doc = new DOMDocument;
    $doc->loadHTML($str_in);
    process($doc->documentElement, $replaceRules);
    return html_entity_decode($doc->saveHTML());
}

Примечание: Не нужно беспокоиться, если HTML плохо структурирован (как в вашем примере);однако, вывод будет хорошо структурирован.

Кредит, где он должен: Рекурсивная функция process(), которая выполняет большую часть реальной работы, поступает прямо из ответа Лукаша Лалинского на Как заменить текст в HTML .addLinks() - это всего лишь пример использования, адаптированный к вашему вопросу.

0 голосов
/ 15 сентября 2011

Не уверен, почему у вас такая большая конструкция, когда что-то вроде:

$str_out = preg_replace('/(' . preg_quote(implode('|', array_keys($replaces))) . ')/', $replaces[$1], $str_in);

может достичь примерно того же самого.Конечно, использование регулярных выражений для обработки HTML - это опасный процесс .Вы должны использовать DOM с некоторым xpath, чтобы сделать это более надежно.

...