¿Encontrar una cadena de texto usando jQuery?

241

Digamos que una página web tiene una cadena como "Soy una cadena simple" que quiero encontrar. ¿Cómo haría esto usando JQuery?

Keith Donegan
fuente

Respuestas:

327

jQuery tiene el método contiene. Aquí hay un fragmento para ti:

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

El selector anterior selecciona cualquier elemento que contenga la cadena de destino. El foundin será un objeto jQuery que contiene cualquier elemento coincidente. Consulte la información de la API en: https://api.jquery.com/contains-selector/

Una cosa a tener en cuenta con el comodín '*' es que obtendrá todos los elementos, incluidos los elementos html an body, que probablemente no desee. Es por eso que la mayoría de los ejemplos en jQuery y otros lugares usan $ ('div: contiene ("Soy una cadena simple")')

Tony Miller
fuente
12
@ Tony, ¿cómo haría para manipular solo el texto coincidente y no solo el párrafo completo, div, etc.?
Keith Donegan
12
Debería señalar que esto distingue entre mayúsculas y minúsculas. Un usuario llamado "yo" escribió esto en la página de documentos de jQuery: $ .expr [':']. Icontains = function (obj, index, meta, stack) {return (obj.textContent || obj.innerText || jQuery ( obj) .text () || '') .toLowerCase (). indexOf (meta [3] .toLowerCase ())> = 0; }; Ejemplo: $ ("div: icontains ('John')"). Css ("decoración de texto", "subrayado");
Brandon Bloom
funciona esto para json? ¿Qué sucede si quiero filtrar texto en un valor json?
Chamilyan
55
Esto no funcionará si el nodo de texto tiene un salto de línea, por ejemplo. "Soy una cadena \ n simple". Tenga en cuenta que el salto de línea no se representará, por lo que el usuario ni siquiera sabrá dónde está el problema. Todas estas soluciones tienen este problema. Ver jsfiddle.net/qPeAx
jesper
99
-1, no funciona. Devuelve todos los nodos principales en el árbol, solo desea el más bajo.
TMS
51

Normalmente, los selectores jQuery no buscan dentro de los "nodos de texto" en el DOM. Sin embargo, si usa la función .contents (), se incluirán nodos de texto, entonces puede usar la propiedad nodeType para filtrar solo los nodos de texto y la propiedad nodeValue para buscar la cadena de texto.

    $ ('*', 'cuerpo')
        .andSelf ()
        .contenido()
        .filter (function () {
            devuelve this.nodeType === 3;
        })
        .filter (function () {
            // Solo coincide cuando contiene 'cadena simple' en cualquier parte del texto
            devuelve this.nodeValue.indexOf ('cadena simple')! = -1;
        })
        .each (function () {
            // Haz algo con this.nodeValue
        });
BarelyFitz
fuente
8
Para aclarar, como Tony mencionó, puede usar el selector ": contiene ()" para buscar dentro de los nodos de texto, pero jQuery no devolverá los nodos de texto individuales en los resultados (solo una lista de elementos). Pero cuando usa .contents (), jQuery devuelve elementos y nodos de texto. Para más información: docs.jquery.com/Traversing/contents
BarelyFitz
55
Estoy desconcertado por qué estás usando .andSelf(). De api.jquery.com/andSelf : "los objetos jQuery mantienen una pila interna que realiza un seguimiento de los cambios en el conjunto de elementos coincidentes. Cuando se llama a uno de los métodos de recorrido DOM, el nuevo conjunto de elementos se inserta en la pila. Si también se desea el conjunto de elementos anterior, .andSelf () puede ayudar ". No veo ningún contexto anterior, ¿qué me estoy perdiendo?
Alan H.
1
¡Votado! Debería ser la respuesta aceptada porque filtra todos los nodos principales, lo que creo que es la necesidad común en la mayoría de los escenarios.
LucaM
29

Esto seleccionará solo los elementos de hoja que contienen "Soy una cadena simple".

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

Pegue lo siguiente en la barra de direcciones para probarlo.

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

Si quieres agarrar solo "Soy una cadena simple" . Primero envuelva el texto en un elemento como este.

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

y luego haz esto.

$('*[containsStringImLookingFor]').css("border","solid 2px red");
Delgado
fuente
3
la función .filter () sería más útil que .each () aquí. De hecho, podría ponerlo en un selector: "*: contiene ('bla'): vacío"
nickf
2
#nickf -: vacío no seleccionará un nodo de texto que contenga texto. Por lo tanto, si el nodo de texto contiene "Soy una cadena simple", se excluye. docs.jquery.com/Selectors/empty
Slim
2
Sé que llego un poco tarde aquí, pero ¿esto no ignorará ningún bloque de texto donde la cadena existe en el nivel superior pero hay niños dentro? por ejemplo: <blockquote> Soy una cadena simple <span style = "font-weight: bold;"> VIVIR EN EL BORDE </span> </blockquote>
Ken Bellows
Solo quiero mencionar que "contieneStringImLookingFor" no es un atributo HTML válido. Úselo para HTML 5 "data-contieneStringImLookingFor". No hay forma de que la versión HTML anterior a la 5 agregue atributos personalizados ...
Snickbrack
17

Si solo desea el nodo más cercano al texto que está buscando, puede usar esto:

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

Esto incluso funcionará si su HTML se ve así:

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

El uso del selector anterior encontrará la <strong>etiqueta, ya que es la última etiqueta que contiene toda esa cadena.

nickf
fuente
1
Esto no parece funcionar. En esta página, por ejemplo, *: contiene ("el"): último devuelve solo 1 elemento.
bzlm
44
@bzlm: bueno, no necesariamente especificaba que quería encontrar múltiples ocurrencias.
nickf
2
Ajá. ¿Hay alguna manera de hacerlo funcionar para múltiples ocurrencias? Creo que es una solución más elegante que las que involucran la verificación recursiva del tipo de nodo, etc.
bzlm
1
la única forma en que podría pensar en obtener todos los nodos, pero no todos los antepasados ​​en la línea sería recorrer el resultado, eliminando a todos los padres, aunque podría tener problemas, por ejemplo: <p>my text <b>my text</b></p>- eliminar a los antepasados ​​de la <b>etiqueta perder el otro partido
nickf
13

Eche un vistazo a resaltar (complemento jQuery).

Chris Doggett
fuente
7

Solo agregando a la respuesta de Tony Miller, esto me llevó al 90% hacia lo que estaba buscando pero aún no funcionó. Agregar .length > 0;al final de su código hizo que mi script funcionara.

 $(function() {
    var foundin = $('*:contains("I am a simple string")').length > 0;
 });
Pixelomo
fuente
¿Cómo agregar una nueva palabra en la cadena encontrada ?, quiero agregar un asterisco en ese trabajo encontrado.
userAZLogicApps
@SaMolPP foundin += '*';
Pixelomo
2

Esta función debería funcionar. básicamente realiza una búsqueda recursiva hasta que obtenemos una lista distinta de nodos hoja.

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
fuente