2011-06-29 11 views
22

próbuję zrobić "pogromcę żargonu". Zasadniczo mam pewne html i niektóre terminy słownikowe w bazie danych. Gdy osoba kliknie na Fałszowanie żargonu, zastępuje słowa w tekście ładną podpowiedzką (wztooltip), która pokazuje im znaczenie.Wyszukiwanie i zamiana słów w HTML

Próbowałem ciężko na ten jeden i został ciężko patrząc na to pytanie Regex/DOMDocument - match and replace text not in a link

i wydaje się, że odpowiedź leży w libs simple_html_dom ale mam problemy z dostaniem go do pracy. Oczywiście wszystkie słowa już połączone nie są dotykane. Oto lista tego, co mam.

$html = str_get_html($article['content']); 

$query_glossary = "SELECT word,glossary_term_id,info FROM glossary_terms WHERE status = 1 ORDER BY LENGTH(word) DESC"; 
$result_glossary = mysql_query_run($query_glossary); 

while($glossary = mysql_fetch_array($result_glossary)) { 
    $glossary_link = SITEURL.'/glossary/term/'.string_to_url($glossary['word']).'-'.$glossary['glossary_term_id']; 
    if(strlen($glossary['info'])>400) { 
     $glossary_info = substr(strip_tags($glossary['info']),0,350).' ...<br /> <a href="'.$glossary_link.'">Read More</a>'; 
    } 
    else { 
     $glossary_info = $glossary['info']; 
    } 
    $glossary_tip = 'href="javascript:;" onmouseout="UnTip();" class="article_jargon_highligher" onmouseover="'.tooltip_javascript('<a href="'.$glossary_link.'">'.$glossary['word'].'</a>',$glossary_info,400,1,0,1).'"'; 
    $glossary_word = $glossary['word']; 
    $glossary_word = preg_quote($glossary_word,'/'); 

    //once done we can replace the words with a nice tip  
    foreach ($html->find('text') as $element) { 
     if (!in_array($element->parent()->tag,array())) { 
      //problems are case aren't taken into account and grammer 
      $element->innertext = str_ireplace(''.$glossary['word'].' ',' <a '.$glossary_tip.' >'.$glossary['word'].'</a> ', $element->innertext); 

      //$element->innertext = str_ireplace(''.$glossary['word'].',',' <a '.$glossary_tip.'>'.$glossary['word'].'</a> ', $element->innertext); 
      //$element->innertext = preg_replace ("/\s(".$glossary_word.")\s/ise","nothing(' <a'.'$glossary_tip.'>'.'$1'.'</a> ')" , $element->innertext); 
      // $element->innertext = str_replace('__glossary_tip_replace__',$glossary_tip, $element->innertext); 
     } 
    } 
} 
$article['content'] = $html->save(); 
+0

Jestem kolegą. Prawdziwy problem polega na tym, że mamy kłopot z tym, aby kod dopasowywał tylko słowa invidiaul, a nie słowa wewnątrz słów (np. APS). Te słowa również znajdują się w HTML. To wymaga rozważenia. – David

+0

Jest to z pewnością przypadek pisania wystarczająco mocnego wyrażenia regularnego, prawdopodobnie przy użyciu białych znaków i interpunkcji w celu wykrycia granic słów, chociaż nie będę się zawstydzał próbując.+1 – shanethehat

+0

Czy chcesz rozwiązanie JS lub PHP, ponieważ użyłeś obu tagów? – Gerben

Odpowiedz

11

Użyj słowa odwrócony znak \W wybrać do celów innych niż cyfry i litery w swojej strukturze regex znaków. Ponieważ nadal będzie to niemożliwe na granicach obszaru blobu tekstowego, należy również przetestować te warunki. Tak więc użycie słowa „termin” jako tekst szukasz:

(^term$)|(^term\W)|(\Wterm\W)|(\Wterm$) 

Pierwsze kontrole stanu, aby upewnić się, że termin ten nie jest tylko zawartość blob, drugi sprawdza, czy jego pierwsze słowo, trzeci, jeśli zawiera się w kropli, a ostatni, jeśli jest ostatnim słowem.

Jeśli chcesz uwzględnić dowolne inne znaki jako znaki słowne (powiedzmy myślnik), musisz zmienić nazwę \W na [^\w\-].

Mam nadzieję, że to pomoże. Prawdopodobnie istnieją również optymalizacje, ale powinno to być przynajmniej dobry punkt wyjścia.

+0

Może również po prostu dołączyć '^' i '$' w '[]' –

+2

^inside [] oznacza coś innego. A $ będzie mapować na znak dolara. Można jednak zrobić coś takiego (^ | \ W) (termin) (\ W | $) – Gerben

+0

@ Gerben znacznie lepiej! Ale myśląc o tym więcej, ten (i poprzedni wzorzec) przedstawia teraz inny problem: nie-słowa będą również zawarte w dopasowaniu. Będzie to wymagać dodatkowej logiki, aby je wykluczyć ... – Rodaine

8

Zakładając, że wszystkie słowniki "słowa" składają się ze standardowych "słownych" znaków (tj. [A-Za-z0-9_]), to proste asercja brzegów słów może być umieszczone przed i za słowem w wzorze regex. Spróbuj wymienić pertinant oświadczenie z tym:

$element->innertext = preg_replace(
    '/\b'. $glossary_word .'\b/i', 
    '<a '. $glossary_tip .' >'. $glossary['word'] .'</a>', 
    $element->innertext); 

ta zakłada, że ​​$glossary_word został uruchomiony koryta preg_quote (co robi Twój kod).

Jednakże, jeśli słowa słownika mogą zawierać inne niestandardowe znaki słowne (takie jak myślnik '-'), można sformułować bardziej złożone wyrażenie, które zawiera poprzednią linię i lookbehind, aby upewnić się, że tylko całe słowa są dopasowane. Na przykład:

$re_pattern = "/   # Match a glossary whole word. 
    (?<=[\s'\"]|^)  # Word preceded by whitespace, quote or BOS. 
    {$glossary_word}  # Word to be matched. 
    (?=[\s'\".?!,;:]|$) # Word followed by ws, quote, punct or EOS. 
    /ix"; 
+0

Tak, miałem problem z tym, że te słowa nie pasują do formatu słowa –

+0

@Richard Housham: Drugie, dłuższe wyrażenie będzie działało dla _any_ słowa (lub nawet frazy zawierającej spacje). – ridgerunner

3

miałem tego problemu w JS dostaniem poszczególne słowa. To, co zrobiłem, było następujące (możesz przetłumaczyć je z JS na PHP):

To naprawdę działa NAPRAWDĘ dobrze dla mnie. :)

var words = document.body.innerHTML; 

// FIRST PASS 

// remove scripts 
words = words.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, ''); 
// remove CSS 
words = words.replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, ''); 
// remove comments 
words = words.replace(/<!--[\s\S]*?-->/g, ''); 
// remove html character entities 
words = words.replace(/&.*?;/g, ' '); 
// remove all HTML 
words = words.replace(/<[\s\S]*?>/g, ''); 

// SECOND PASS 

// remove all newlines 
words = words.replace(/\n/g, ' '); 
// replace multiple spaces with 1 space 
words = words.replace(/\s{2,}/g, ' '); 

// split each word 
words = words.split(/[^a-z-']+/gi); 
Powiązane problemy