Rechercher une chaîne de texte à l'aide de jQuery?

241

Supposons qu'une page Web comporte une chaîne telle que "Je suis une chaîne simple" que je souhaite rechercher. Comment pourrais-je procéder à l'aide de JQuery?

Keith Donegan
la source

Réponses:

327

jQuery a la méthode contains. Voici un extrait pour vous:

<script type="text/javascript">
$(function() {
    var foundin = $('*:contains("I am a simple string")');
});
</script>

Le sélecteur ci-dessus sélectionne tout élément contenant la chaîne cible. Le foundin sera un objet jQuery qui contient tout élément correspondant. Voir les informations de l'API sur: https://api.jquery.com/contains-selector/

Une chose à noter avec le caractère générique «*» est que vous obtiendrez tous les éléments, y compris vos éléments html et body, dont vous ne voulez probablement pas. C'est pourquoi la plupart des exemples de jQuery et d'autres endroits utilisent $ ('div: contains ("I am a simple string")')

Tony Miller
la source
12
@Tony, comment pourrais-je manipuler uniquement le texte correspondant et pas seulement tout le parapgraphe, div, etc., etc.?
Keith Donegan
12
Doit souligner que cela est sensible à la casse. Un utilisateur nommé "moi" a écrit ceci sur la page des documents jQuery: $ .expr [':']. Icontains = function (obj, index, meta, stack) {return (obj.textContent || obj.innerText || jQuery ( obj) .text () || '') .toLowerCase (). indexOf (meta [3] .toLowerCase ())> = 0; }; Exemple: $ ("div: icontains ('John')"). Css ("text-decoration", "underline");
Brandon Bloom
est-ce que cela fonctionne pour json? Que faire si je veux filtrer du texte dans une valeur json?
Chamilyan
5
Cela ne fonctionnera pas si le nœud de texte a un saut de ligne, par exemple. "Je suis une simple chaîne \ n". Notez que le saut de ligne ne sera pas rendu, donc l'utilisateur ne saura même pas où est le problème. Toutes ces solutions ont ce problème. Voir jsfiddle.net/qPeAx
jesper
9
-1, ne fonctionne pas. Il renvoie tous les nœuds parents dans l'arborescence, vous ne voulez que le plus bas.
TMS
51

Normalement, les sélecteurs jQuery ne recherchent pas dans les «nœuds de texte» du DOM. Cependant, si vous utilisez la fonction .contents (), les nœuds de texte seront inclus, vous pouvez alors utiliser la propriété nodeType pour filtrer uniquement les nœuds de texte et la propriété nodeValue pour rechercher la chaîne de texte.

    $ ('*', 'corps')
        .etSelf ()
        .Contenu()
        .filter (fonction () {
            renvoyer this.nodeType === 3;
        })
        .filter (fonction () {
            // Correspond uniquement lorsque contient une "chaîne simple" n'importe où dans le texte
            renvoie this.nodeValue.indexOf ('chaîne simple')! = -1;
        })
        .each (fonction () {
            // Faites quelque chose avec this.nodeValue
        });
BarelyFitz
la source
8
Pour clarifier, comme Tony l'a mentionné, vous pouvez utiliser le sélecteur ": contains ()" pour rechercher dans les nœuds de texte, mais jQuery ne renverra pas les nœuds de texte individuels dans les résultats (juste une liste d'éléments). Mais lorsque vous utilisez .contents (), jQuery renvoie à la fois des éléments et des nœuds de texte. Pour plus d'informations: docs.jquery.com/Traversing/contents
BarelyFitz
5
Je suis perplexe quant à la raison pour laquelle vous utilisez .andSelf(). Depuis api.jquery.com/andSelf : "Les objets jQuery conservent une pile interne qui conserve la trace des modifications apportées à l'ensemble d'éléments mis en correspondance. Lorsqu'une des méthodes de parcours DOM est appelée, le nouvel ensemble d'éléments est poussé vers la pile. Si l'ensemble d'éléments précédent est également souhaité. .andSelf () peut vous aider. " Je ne vois aucun contexte précédent, que me manque-t-il?
Alan H.Jan
1
A voté! Devrait être la réponse acceptée car elle filtre tous les nœuds parents qui, je pense, sont le besoin commun dans la plupart des scénarios.
LucaM
29

Cela sélectionnera uniquement les éléments feuilles qui contiennent "Je suis une simple chaîne".

$('*:contains("I am a simple string")').each(function(){
     if($(this).children().length < 1) 
          $(this).css("border","solid 2px red") });

Collez ce qui suit dans la barre d'adresse pour le tester.

javascript: $('*:contains("I am a simple string")').each(function(){ if($(this).children().length < 1) $(this).css("border","solid 2px red") }); return false;

Si vous voulez saisir juste "Je suis une simple chaîne" . Enveloppez d'abord le texte dans un élément comme celui-ci.

$('*:contains("I am a simple string")').each(function(){
     if($(this).children().length < 1) 
          $(this).html( 
               $(this).text().replace(
                    /"I am a simple string"/
                    ,'<span containsStringImLookingFor="true">"I am a simple string"</span>' 
               )  
           ) 
});

puis faites cela.

$('*[containsStringImLookingFor]').css("border","solid 2px red");
Svelte
la source
3
la fonction .filter () serait plus utile que .each () ici. En fait, vous pouvez le mettre dans un seul sélecteur: "*: contient ('blah'): vide"
nickf
2
#nickf -: vide ne sélectionnera pas un nœud de texte contenant du texte. Donc, si le nœud de texte contient "Je suis une simple chaîne", il est exclu. docs.jquery.com/Selectors/empty
Slim
2
Je sais que je suis un peu en retard ici, mais cela n'ignore-t-il pas les blocs de texte où la chaîne existe au niveau supérieur mais qui contient des enfants? par exemple: <blockquote> Je suis une simple chaîne <span style = "font-weight: bold;"> LIVING ON THE EDGE </span> </blockquote>
Ken Bellows
Je veux juste mentionner que "containsStringImLookingFor" n'est pas un attribut HTML valide. Veuillez utiliser pour HTML 5 "data-containsStringImLookingFor". Il n'y a aucun moyen pour la version HTML antérieure à 5 d'ajouter des attributs personnalisés ...
Snickbrack
17

Si vous voulez juste le nœud le plus proche du texte que vous recherchez, vous pouvez utiliser ceci:

$('*:contains("my text"):last');

Cela fonctionnera même si votre code HTML ressemble à ceci:

<p> blah blah <strong>my <em>text</em></strong></p>

L'utilisation du sélecteur ci-dessus trouvera la <strong>balise, car c'est la dernière balise qui contient toute cette chaîne.

nickf
la source
1
Cela ne semble pas fonctionner. Sur cette page, par exemple, *: contient ("le"): dernier ne renvoie qu'un seul élément.
bzlm
4
@bzlm: eh bien, cela ne précisait pas nécessairement qu'il voulait trouver plusieurs occurrences.
nickf
2
Aha. Existe-t-il un moyen de le faire fonctionner pour plusieurs occurrences? Je pense que c'est une solution plus élégante que celles impliquant la vérification récursive du type de nœud, etc.
bzlm
1
la seule façon dont je pourrais penser à obtenir tous les nœuds, mais pas tous les ancêtres sur la ligne serait de parcourir le résultat, en supprimant tous les parents, mais vous pourriez avoir des problèmes, par exemple: <p>my text <b>my text</b></p>- supprimer les ancêtres de la <b>balise serait perdre l'autre match
nickf
7

J'ajoute simplement à la réponse de Tony Miller, car cela m'a permis d'atteindre 90% de ce que je cherchais, mais cela n'a toujours pas fonctionné. L'ajout .length > 0;à la fin de son code a fait fonctionner mon script.

 $(function() {
    var foundin = $('*:contains("I am a simple string")').length > 0;
 });
Pixelomo
la source
comment ajouter un nouveau mot sur la chaîne trouvée?, je veux ajouter un astérisque sur ce travail trouvé.
userAZLogicApps
@SaMolPP foundin += '*';
Pixelomo
2

cette fonction devrait fonctionner. fait essentiellement une recherche récursive jusqu'à ce que nous obtenions une liste distincte de nœuds foliaires.

function distinctNodes(search, element) {
    var d, e, ef;
    e = [];
    ef = [];

    if (element) {
        d = $(":contains(\""+ search + "\"):not(script)", element);
    }
    else {
            d = $(":contains(\""+ search + "\"):not(script)");
    }

    if (d.length == 1) {
            e.push(d[0]);
    }
    else {
        d.each(function () {
            var i, r = distinctNodes(search, this);
            if (r.length === 0) {
                e.push(this);
            }
            else {
                for (i = 0; i < r.length; ++i) {
                    e.push(r[i]);
                }
            }
        });
    }
    $.each(e, function () {
        for (var i = 0; i < ef.length; ++i) {
            if (this === ef[i]) return;
        }
        ef.push(this);
    });
    return ef;
}
danatcofo
la source