2009-10-14 52 views
2

從這個問題:What regex pattern do I need for this?我一直在使用下面的代碼:如何替換文本在HTML

function process($node, $replaceRules) { 
    if($node->hasChildNodes()) { 
     foreach ($node->childNodes 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); 
      } 
     } 
    } 
} 

$replaceRules = array(
    '/\b(c|C)olor\b/' => '$1olour', 
    '/\b(kilom|Kilom|M|m)eter/' => '$1etre', 
); 

$htmlString = "<p><span style='color:red'>The color of the sky is: gray</p>"; 
$doc = new DOMDocument(); 
$doc->loadHtml($htmlString); 
process($doc, $replaceRules); 
$string = $doc->saveHTML(); 
echo mb_substr($string,119,-15); 

它工作正常,但它失敗(如子節點被替換的第一個實例),如果html有文本和HTML。所以它適用於

<div>The distance is four kilometers</div> 

但不

<div>The distance is four kilometers<br>1000 meters to a kilometer</div> 

<div>The distance is four kilometers<div class="guide">1000 meters to a kilometer</div></div> 

,將這樣的例子工作方法的任何想法?

回答

2

調用$node->replaceChild會混淆$node->childNodes迭代器。你可以先得到子節點,然後處理它們:

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); 
      } 
     } 
    } 
} 
+0

太棒了。非常感謝。 – Apemantus 2009-10-14 12:33:29

+1

+1真正的輝煌。我借用這個來回答[類似的問題](http://stackoverflow.com/questions/7436245/php-token-replaces-html-entities/7438068#7438068),並記入你。我最近看到很多這樣的問題,所以我會「贊」它。 :) – Herbert 2011-09-15 22:24:51