2011-06-29 31 views
22

lo que estoy tratando de hacer es crear un 'destructor de jerga'. Básicamente tengo algunos html y algunos términos del glosario en una base de datos. Cuando la persona hace clic en el modificador de jerga reemplaza las palabras en el texto con una buena información sobre herramientas (wztooltip) que les muestra los significados.Buscar y reemplazar palabras en HTML

he estado tratando duro en éste y estado buscando en gran medida a esta pregunta Regex/DOMDocument - match and replace text not in a link

y parece que la respuesta está en las librerías simple_html_dom pero estoy teniendo problemas para conseguir que funcione. Obviamente, las palabras ya vinculadas no se tocan. Aquí hay una lista de lo que tengo.

$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

Soy un colega. El verdadero problema es que estamos teniendo problemas para conseguir que el código solo coincida con las palabras de invidiaul y no con las palabras dentro de las palabras (es decir, con APS tal vez). Estas palabras están dentro de HTML también. Entonces eso necesita considerar. – David

+0

Seguramente es solo el caso de escribir una expresión regular lo suficientemente potente, probablemente usando espacios en blanco y signos de puntuación para detectar límites de palabras, aunque no me avergonzaré por intentarlo.+1 – shanethehat

+0

¿Desea una solución JS o una solución PHP, porque usó ambas etiquetas? – Gerben

Respuesta

11

utilizar el carácter de la palabra invertida \W para seleccionar caracteres que no sean números y letras en su patrón de expresión regular. Como esto aún fallaría en los límites del blob de texto, también necesitaría probar esas condiciones. Por lo tanto el uso de la palabra 'término' que el texto que está buscando:

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

la condición de primer comprobaciones para asegurarse de que ese término no es el único contenido de la burbuja, el segundo Analiza si su primera palabra, el tercero si estaba dentro del blob, y el último si es la última palabra.

Si desea considerar cualquier otro carácter como caracteres de palabra (por ejemplo, un guion), deberá devolver el \W con .

Espero que esto ayude. Probablemente haya optimizaciones que también se puedan realizar, pero al menos esto debería ser un buen punto de partida.

+0

También puede incluir simplemente '^' y '$' en '[]' –

+2

^inside [] significa algo más. Y $ se asignaría al signo de dólar. ¡Sin embargo, podría hacer algo como (^ | \ W) (término) (\ W | $) – Gerben

+0

@Gerben mucho mejor! Pero, al pensarlo un poco más, este (y mi patrón anterior) ahora presenta otro problema: los personajes sin palabras también se incluirían en el partido. Esto requerirá lógica adicional para excluirlos ... – Rodaine

8

Suponiendo que todas las "palabras" del glosario consisten en caracteres estándar de "palabra" (es decir, [A-Za-z0-9_]), se puede colocar una afirmación de límite de palabra simple antes y después de la palabra en el patrón de expresión regular. Trate de reemplazar la declaración pertinant con esto:

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

Esto supone que $glossary_word se ha ejecutado a través preg_quote (que hace su código).

Sin embargo, si las palabras del glosario pueden contener otros caracteres no estándar (como un guión '-'), se puede formular una expresión regular más compleja que incorpore lookahead y lookbehind para garantizar que solo coincidan palabras completas. Por ejemplo:

$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

Sí, tuve este problema es que las palabras no coinciden con el formato de la palabra –

+0

@Richard Housham: La segunda, la expresión regular más larga funcionará para cualquier palabra (o incluso una frase que contenga espacios para el caso). – ridgerunner

3

tuve este problema en conseguir JS palabras individuales. Lo que hice fue lo siguiente (puedes traducirlo de JS a PHP):

Realmente funciona REALMENTE bien para mí. :)

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