2008-11-11 10 views
50

Je dois mettre en évidence, insensible à la casse, les mots-clés donnés dans une chaîne JavaScript.Remplacement de chaîne insensible à la casse en JavaScript?

Par exemple:

  • highlight("foobar Foo bar FOO", "foo") devrait retourner "<b>foo</b>bar <b>Foo</b> bar <b>FOO</b>"

J'ai besoin du code pour travailler pour un mot-clé, et donc une expression régulière comme /foo/i est hardcoded pas une solution suffisante.

Quelle est la manière la plus simple de le faire?

(Cette instance d'un problème plus général décrit dans le titre, mais je pense qu'il est préférable d'aborder avec un béton, par exemple utile.)

Répondre

67

Vous pouvez utiliser des expressions régulières si vous préparez la recherche chaîne. En PHP, par exemple il y a une fonction preg_quote, qui remplace tous les regex-chars dans une chaîne avec leurs versions échappées.

Voici d'une telle fonction de javascript:

function preg_quote(str) { 
    // http://kevin.vanzonneveld.net 
    // + original by: booeyOH 
    // + improved by: Ates Goral (http://magnetiq.com) 
    // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 
    // + bugfixed by: Onno Marsman 
    // *  example 1: preg_quote("$40"); 
    // *  returns 1: '\$40' 
    // *  example 2: preg_quote("*RRRING* Hello?"); 
    // *  returns 2: '\*RRRING\* Hello\?' 
    // *  example 3: preg_quote("\\.+*?[^]$(){}=!<>|:"); 
    // *  returns 3: '\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:' 

    return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1"); 
} 

(Extrait de http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_preg_quote/)

Vous coudl procédez comme suit:

function highlight(data, search) 
{ 
    return data.replace(new RegExp("(" + preg_quote(search) + ")" , 'gi'), "<b>$1</b>"); 
} 
+0

Je ne pense pas que votre exemple fonctionne. – tvanfosson

+0

Je vois, seule la première occurrence est remplacée. Je ne savais pas que remplacer se comporte comme ça. Le preg_quote est important s'il veut mettre en évidence des chaînes avec/ou * ou d'autres caractères regex. – okoman

+0

Um .. c'est * est * javascript. Je viens de dire qu'il y a une fonction en PHP appelée preg_quote. Puis j'ai inclus une version js de cette fonction et une fonction js ... ces exemples de code * sont * js – okoman

0

Pourquoi ne pas simplement créer un nouveau regex sur chaque appel à votre fonction? Vous pouvez utiliser:

new Regex([pat], [flags]) 

où [pat] est une chaîne pour le motif, et [drapeaux] sont les drapeaux.

63
function highlightWords(line, word) 
{ 
    var regex = new RegExp('(' + word + ')', 'gi'); 
    return line.replace(regex, "<b>$1</b>"); 
} 
+1

Bien sûr, vous devez faire attention à ce que vous remplacez et à ce que vous recherchez en tant que notes @bobince . Ce qui précède fonctionnera bien pour le texte brut et la plupart des recherches si vous faites attention à citer vos caractères regex ... – tvanfosson

+1

exactement ce dont j'avais besoin :) thx – daniellmb

+0

Cela va rencontrer des problèmes si il y a des caractères regex dans le mot en cours de remplacement. La solution de @ okoman contourne cela. –

5

Les expressions régulières sont très bien tant que mots-clés sont vraiment des mots, vous pouvez simplement utiliser un constructeur RegExp au lieu d'un littéral pour créer un à partir une variable:

var re= new RegExp('('+word+')', 'gi'); 
return s.replace(re, '<b>$1</b>'); 

La difficulté se pose si « mots-clés 'peut avoir de la ponctuation, car la ponctuation tend à avoir une signification spéciale dans les expressions rationnelles. Malheureusement, contrairement à la plupart des autres langages/bibliothèques avec le support de regexp, il n'y a pas de fonction standard pour échapper à la ponctuation pour les expressions rationnelles en JavaScript.

Et vous ne pouvez pas savoir exactement quels caractères doivent s'échapper car l'implémentation de regexp de chaque navigateur n'est pas forcément identique. (En particulier, les nouveaux navigateurs peuvent ajouter de nouvelles fonctionnalités.) Et les caractères d'échappement antislash qui ne sont pas spéciaux ne sont pas garantis pour continuer à fonctionner, bien qu'en pratique cela soit le cas.

donc sur le mieux que vous pouvez faire est l'un des:

  • essayant d'attraper chaque caractère spécial dans l'usage commun du navigateur aujourd'hui [ajouter: voir la recette de Sebastian]
  • antislash échapper à tous les non-caractères alphanumériques. care: \ W correspondra également aux caractères Unicode non-ASCII, que vous ne voulez pas vraiment.
  • simplement veiller à ce qu'il n'y ait pas non-caractères alphanumériques dans le mot-clé avant de rechercher

Si vous utilisez ce pour mettre en évidence les mots au format HTML qui a déjà un balisage dans, cependant, vous avez du mal. Votre «mot» peut apparaître dans un nom d'élément ou une valeur d'attribut, auquel cas essayer d'envelopper un < b> autour de lui provoquera une brisure. Dans des scénarios plus complexes peut-être même un trou de sécurité d'injection HTML vers XSS. Si vous devez faire face à un balisage, vous aurez besoin d'une approche plus compliquée, en divisant le balisage '< ...> avant d'essayer de traiter chaque tronçon de texte seul.

13

Vous pouvez améliorer l'objet RegExp avec une fonction qui fait caractère spécial échapper pour vous:

RegExp.escape = function(str) 
{ 
    var specials = /[.*+?|()\[\]{}\\$^]/g; // .*+?|()[]{}\$^ 
    return str.replace(specials, "\\$&"); 
} 

Ensuite, vous pourrez utiliser ce que les autres ont suggéré sans aucun souci:

function highlightWordsNoCase(line, word) 
{ 
    var regex = new RegExp("(" + RegExp.escape(word) + ")", "gi"); 
    return line.replace(regex, "<b>$1</b>"); 
} 
+0

? en javascript RegExp doit être échappé avec des doubles barres obliques inverses comme \\? – Jerinaw

+0

@Jerinaw Que penses-tu de ma fonction 'RegExp.escape'? – Tomalak

+0

http://stackoverflow.com/questions/889957/escaping-question-mark-in-regex-javascript J'ai rencontré des problèmes où le point d'interrogation devait être échappé avec double \ mais je suppose que dans [] vous ne faites pas ' t besoin d'y échapper. – Jerinaw

4

Qu'en est-il quelque chose comme ceci:

if(typeof String.prototype.highlight !== 'function') { 
    String.prototype.highlight = function(match, spanClass) { 
    var pattern = new RegExp(match, "gi"); 
    replacement = "<span class='" + spanClass + "'>$&</span>"; 

    return this.replace(pattern, replacement); 
    } 
} 

Cela pourrait alors être appelé comme suit:

var result = "The Quick Brown Fox Jumped Over The Lazy Brown Dog".highlight("brown","text-highlight"); 
1

Pour les pauvres disregexia ou regexophobia:

function replacei(str, sub, f){ 
 
\t let A = str.toLowerCase().split(sub.toLowerCase()); 
 
\t let B = []; 
 
\t let x = 0; 
 
\t for (let i = 0; i < A.length; i++) { 
 
\t \t let n = A[i].length; 
 
\t \t B.push(str.substr(x, n)); 
 
\t \t if (i < A.length-1) 
 
\t \t \t B.push(f(str.substr(x + n, sub.length))); 
 
\t \t x += n + sub.length; 
 
\t } 
 
\t return B.join(''); 
 
} 
 

 
s = 'Foo and FOO (and foo) are all -- Foo.' 
 
t = replacei(s, 'Foo', sub=>'<'+sub+'>') 
 
console.log(t)

Sortie:

<Foo> and <FOO> (and <foo>) are all -- <Foo>. 
Questions connexes