Prova questo. L'idea è di sostituire i tag A con un valore calcolato per poi ripristinarli.

Codice PHP:
<?php
//----- Il testo
$text   "Ciao a tutti, ho creato questa funzione che rende indirizzi email e link cliccabili, 
poi analizza il testo alla ricerca di parole errate (le parole 'giuste' 
sono contenute in un db), che vengono <a href='http://www.mio_sito.it'>sottolineate di rosso</a>. Il problema e' che anche le parole 
all'interno dei link vengono sottolineate, rendendo di fatto il link <a href='http://www.my_site.co.uk'>inutilizzabile</a>. Per capirci se in input
 inserisco 'foo@bar.it' mi restituisce '<u>foo</u>@bar.<u>it</u>'. Come posso fare per far riconoscere alla 
 funzione i <a href='http://www.mon_site.fr'>link</a> in modo che non vengono considerati come parole errate? Grazie"
;


//=============================================
// Si rimpiazzano i tag A con un valore unico
// poco probabile
//=============================================
//----- Il pattern
$pattern "/(<\s*a\s*([^>]*)\s*>(.*?)<\/\s*a\s*>)/si";
//----- cerco tutti i tag A e li metto in $occurrences
preg_match_all($pattern,$text,$array);
$occurrences $array[1];
//----- rimpiazzo i tag A 
$listTagA    = array();
$listRepStr  = array();
foreach(
$occurrences as $key => $value) {
 
//----- Rimpiazzo ogni tag A con un valore poco probabile
 //      che comunque è una parola
 
$replace      "azertyuiop${key}poiuytreza";
 
$listRepStr[] = $replace;
 
$listTagA[]   = $value;
 
$text         str_replace($value,$replace,$text);
// foreach($occurrences as $key => $value)
//=============================================


//=============================================
// Questa è la tua parte
//=============================================
$text        nl2br($text); //aggiungo <br> al posto di \r\n
$text2       str_replace('\'',' ',strip_tags($text)); //elimino tags html e sostituisco gli apostrofi con uno spazio
$words       array_unique(str_word_count($text21'1234567890')); //divido il testo in singole parole, elimino i doppioni e le metto nell'array
$list        implode("','",$words); //creo lista delle parole da usare nella query
  
$vocabolario = array('pippo','pluto');
    
    foreach (
$words as $parola)
    {
    
//=====> Se la parola NON corrisponde a un tag A <=======
    
if (!in_array(strtolower($parola),$listRepStr)) {
        if (!
in_array(strtolower($parola),$vocabolario))
        {
        
$replacement"<u>$parola</u>";
        
$text preg_replace("/\b$parola\b/i"$replacement$text);
        }
   }
    }
//=============================================


//=============================================
// Si ripristinano i tag A 
//=============================================
//----- Ripristino i tag A
$text str_replace($listRepStr,$listTagA,$text);  
print 
$text;
//=============================================
  
 
?>