Znajdź ciąg tekstowy za pomocą jQuery?

241

Powiedzmy, że strona internetowa ma ciąg taki jak „Jestem prostym ciągiem”, który chcę znaleźć. Jak mam to zrobić za pomocą JQuery?

Keith Donegan
źródło

Odpowiedzi:

327

jQuery ma metodę zawiera. Oto fragment dla Ciebie:

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

Selektor powyżej wybiera dowolny element zawierający ciąg docelowy. Foundin będzie obiektem jQuery zawierającym dowolny dopasowany element. Zobacz informacje API na: https://api.jquery.com/contains-selector/

Jedną rzeczą, na którą należy zwrócić uwagę za pomocą symbolu wieloznacznego „*”, jest to, że otrzymasz wszystkie elementy, w tym HTML i elementy treści, których prawdopodobnie nie chcesz. Dlatego większość przykładów w jQuery i innych miejscach używa $ („div: zawiera („ Jestem prosty ciąg znaków ”)”)

Tony Miller
źródło
12
@ Tony, jak mógłbym zająć się manipulowaniem tylko pasującym tekstem, a nie tylko całym parapgraphem, div itp.?
Keith Donegan
12
Należy zauważyć, że w tym rozróżniana jest wielkość liter. Użytkownik o nazwie „ja” napisał to na stronie dokumentacji jQuery: $ .expr [':']. Icontains = function (obj, index, meta, stack) {return (obj.textContent || obj.innerText || jQuery ( obj) .text () || '') .toLowerCase (). indexOf (meta [3] .toLowerCase ())> = 0; }; Przykład: $ („div: icontains ('John')”). Css („dekoracja tekstu”, „podkreślenie”);
Brandon Bloom,
czy to działa dla JSona? Co jeśli chcę przefiltrować tekst w wartości JSON?
Chamilyan
5
To nie zadziała, jeśli węzeł tekstowy ma podział wiersza np. „Jestem prostym ciągiem \ n”. Pamiętaj, że podział linii nie będzie renderowany, więc użytkownik nie będzie nawet wiedział, gdzie jest problem. Wszystkie te rozwiązania mają ten problem. Zobacz jsfiddle.net/qPeAx
jesper
9
-1, nie działa. Zwraca wszystkie węzły nadrzędne w drzewie, chcesz tylko najniższy.
TMS
51

Zazwyczaj selektory jQuery nie wyszukują w „węzłach tekstowych” w DOM. Jeśli jednak użyjesz funkcji .contents (), zostaną uwzględnione węzły tekstowe, możesz użyć właściwości nodeType do filtrowania tylko węzłów tekstowych, a właściwości nodeValue do przeszukania ciągu tekstowego.

    $ („*”, „body”)
        .andSelf ()
        .zawartość()
        .filter (function () {
            return this.nodeType === 3;
        })
        .filter (function () {
            // Dopasuj tylko wtedy, gdy zawiera „prosty ciąg” w dowolnym miejscu tekstu
            zwraca this.nodeValue.indexOf ('prosty ciąg')! = -1;
        })
        .each (function () {
            // Zrób coś z this.nodeValue
        });
BarelyFitz
źródło
8
Aby to wyjaśnić, jak wspomniał Tony, możesz użyć selektora „: zawiera ()” do wyszukiwania w obrębie węzłów tekstowych, ale jQuery nie zwróci poszczególnych węzłów tekstowych w wynikach (tylko listę elementów). Ale kiedy używasz .contents (), wtedy jQuery zwraca zarówno elementy, jak i węzły tekstowe. Więcej informacji: docs.jquery.com/Traversing/contents
BarelyFitz
5
Zastanawiam się, dlaczego używasz .andSelf(). Od api.jquery.com/andSelf : „Obiekty jQuery utrzymują wewnętrzny stos, który śledzi zmiany w dopasowanym zestawie elementów. Po wywołaniu jednej z metod przejścia DOM nowy zestaw elementów jest wypychany na stos. Jeśli poprzedni zestaw elementów jest również pożądany, .andSelf () może pomóc. " Nie widzę wcześniejszego kontekstu, czego mi brakuje?
Alan H.
1
Pozytywne! Powinno być przyjętą odpowiedzią, ponieważ odfiltrowuje wszystkie węzły nadrzędne, co moim zdaniem jest powszechną potrzebą w większości scenariuszy.
LucaM,
29

Spowoduje to wybranie tylko elementów liścia, które zawierają „Jestem prostym ciągiem”.

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

Wklej następujące elementy w pasku adresu, aby go przetestować.

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

Jeśli chcesz złapać tylko „Jestem prostym ciągiem” . Najpierw zawiń tekst w takim elemencie.

$('*: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>' 
               )  
           ) 
});

a następnie zrób to.

$('*[containsStringImLookingFor]').css("border","solid 2px red");
Szczupły
źródło
3
funkcja .filter () byłaby bardziej przydatna niż .each () tutaj. W rzeczywistości możesz umieścić go w jednym selektorze: „*: zawiera („ bla ”): pusty”
nickf
2
#nickf -: pusty nie wybierze węzła tekstowego zawierającego tekst. Więc jeśli węzeł tekstowy zawiera „Jestem prostym ciągiem”, jest wykluczony. docs.jquery.com/Selectors/empty
Slim
2
Wiem, że jestem tu trochę spóźniony, ale czy to nie zignoruje żadnych bloków tekstowych, w których łańcuch istnieje na najwyższym poziomie, ale są w nim dzieci? np .: <blockquote> Jestem prostym ciągiem <span style = "font-weight: bold;"> ŻYCIE NA KRAWĘDZI </span> </blockquote>
Ken Bellows
Chcę tylko wspomnieć, że „zawieraStringImLookingFor” nie jest prawidłowym atrybutem HTML. Użyj dla HTML 5 „data-zawieraStringImLookingFor”. Wersja HTML wcześniejsza niż 5 nie ma możliwości dodania niestandardowych atrybutów ...
Snickbrack
17

Jeśli chcesz, aby węzeł znajdował się najbliżej szukanego tekstu, możesz użyć tego:

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

Działa to nawet, jeśli Twój HTML wygląda następująco:

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

Użycie powyższego selektora spowoduje znalezienie <strong>znacznika, ponieważ jest to ostatni znacznik, który zawiera cały ciąg.

pseudonim
źródło
1
To nie działa. Na przykład na tej stronie *: zawiera („the”): last zwraca tylko 1 element.
bzlm
4
@bzlm: cóż, niekoniecznie musiało to oznaczać, że chciał znaleźć wiele wystąpień.
nickf
2
Aha. Czy istnieje sposób, aby działał w przypadku wielu wystąpień? Myślę, że jest to bardziej eleganckie rozwiązanie niż te z rekurencyjnym sprawdzaniem typu węzłów itp.
bzlm
1
jedynym sposobem, w jaki mogłem wymyślić wszystkie węzły, ale nie wszyscy przodkowie w linii byliby zapętlający wynik, usuwając wszystkich rodziców, chociaż możesz mieć problemy, np .: <p>my text <b>my text</b></p>- usunięcie przodków <b>tagu przegrać drugi mecz
nickf
7

Po prostu dodałem do odpowiedzi Tony'ego Millera, ponieważ dzięki temu uzyskałem 90% w stosunku do tego, czego szukałem, ale nadal nie działało. Dodanie .length > 0;na końcu jego kodu uruchomiło mój skrypt.

 $(function() {
    var foundin = $('*:contains("I am a simple string")').length > 0;
 });
Pixelomo
źródło
jak dodać nowe słowo do znalezionego łańcucha? Chcę dodać gwiazdkę do tej znalezionej pracy.
userAZLogicApps
@SaMolPP foundin += '*';
Pixelomo,
2

ta funkcja powinna działać. w zasadzie dokonuje rekurencyjnego wyszukiwania, dopóki nie otrzymamy wyraźnej listy węzłów liści.

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
źródło