2012-02-09 10 views
7

Estoy trabajando en esta cosa de filtrado donde tengo alrededor de 50-100 elementos de la lista. Y cada artículos tienen el marcado de la siguiente manera:JavaScript fuzzy search

<li> 
    <input type="checkbox" name="services[]" value="service_id" /> 
    <span class="name">Restaurant in NY</span> 
    <span class="filters"><!-- hidden area --> 
    <span class="city">@city: new york</span> 
    <span class="region">@reg: ny</span> 
    <span class="date">@start: 02/05/2012</span> 
    <span class="price">@price: 100</span> 
    </span> 
</li> 

creé marcado como esto porque solía albergar dudas List.js

Por lo tanto, probablemente ya adivinado, lo que quiero es hacer búsquedas como esto: @region: LA @price: 124 etc. . El problema es que también quiero mostrar más de un elemento, para seleccionar más de ... uno :)

Supongo que esto necesita búsqueda difusa, pero el problema es que no encontré nada funcional.

¿Alguna idea o punto de partida?

// editar: porque tengo una cantidad bastante pequeña de elementos, me gustaría una solución del lado del cliente.

+1

mira esto: http://code.google.com/p/yeti-witch/ - Podría ser de ayuda. – techfoobar

+0

También vea si su requisito le permite mover la parte de búsqueda difusa al lado del servidor (con AJAX) - Si es así, hacerlo con solr sería lo más fácil de hacer. Además del hecho de que puede buscar a través de miles de artículos en poco tiempo. http://lucene.apache.org/solr/ – techfoobar

+0

Techfoobar: gracias, yeti parece ser más como java que javascript. No puedo encontrar la forma de usarlo en mi código existente. Además, solr parece ser Java también. Necesito algo del lado del cliente o PHP. –

Respuesta

5

Un año más tarde, List.js tiene un buen complemento para fuzzy search que funciona bastante bien.

+2

hace la búsqueda pero no es realmente la" búsqueda difusa ". por ejemplo, en su demo" borroso " "consulta:" bruwo "no encuentra" Guybrush Threepwood "... – tborychowski

+0

Puede especificar qué tan difusa quiere que sea la búsqueda. Puede escribir en bruw y se muestra" Guybrush Treepwood ". Es cuando obtiene dos caracteres de la segunda palabra que filtra el resultado. – user393274

1

tengo una pequeña función, buscando una cadena en una matriz (al menos para mí que produce mejores resultados que levenshtein):

function fuzzy(item,arr) { 
    function oc(a) { 
    var o = {}; for (var i=0; i<a.length; i++) o[a[i]] = ""; return o; 
    } 
    var test = []; 
    for (var n=1; n<=item.length; n++) 
    test.push(item.substr(0,n) + "*" + item.substr(n+1,item.length-n)); 
    var result = []; 
    for (var r=0; r<test.length; r++) for (var i=0; i<arr.length; i++) { 
    if (arr[i].toLowerCase().indexOf(test[r].toLowerCase().split("*")[0]) != -1) 
    if (arr[i].toLowerCase().indexOf(test[r].toLowerCase().split("*")[1]) != -1) 
    if (0 < arr[i].toLowerCase().indexOf(test[r].toLowerCase().split("*")[1]) 
      - arr[i].toLowerCase().indexOf(test[r].toLowerCase().split("*")[0] < 2)) 
    if (!(arr[i] in oc(result))) result.push(arr[i]); 
    } 
    return result; 
} 
+1

¿Por qué llama al 'arr [i] .toLowerCase(). IndexOf (prueba [ r] .toLowerCase(). split ("*") ' una y otra vez! – Metalstorm

20

que estaba buscando "búsqueda difusa" en javascript, pero Haven' Encontré una solución aquí, así que escribí mi propia función que hace lo que necesito.

el algoritmo es muy simple: bucle a través de cartas de aguja y compruebe si se producen en el mismo orden en el pajar:

String.prototype.fuzzy = function (s) { 
    var hay = this.toLowerCase(), i = 0, n = -1, l; 
    s = s.toLowerCase(); 
    for (; l = s[i++] ;) if (!~(n = hay.indexOf(l, n + 1))) return false; 
    return true; 
}; 

por ejemplo:

('a haystack with a needle').fuzzy('hay sucks'); // false 
('a haystack with a needle').fuzzy('sack hand'); // true 
+1

esta debería ser la respuesta aceptada! –

0

No estaba No estoy satisfecho con list.js, así que creé el mío. Probablemente esta no sea exactamente una búsqueda difusa, pero no sé cómo llamarla. Simplemente quería que coincida con una consulta sin tener en cuenta el orden de mis palabras en la consulta.

cuenta la situación siguiente:

  • existe una colección de artículos en la memoria
  • orden de aparición palabras de consulta no importa (por ejemplo,"Hola mundo" vs "hola mundo")
  • El código debe ser fácilmente legible

He aquí un ejemplo:

var articles = [{ 
    title: '2014 Javascript MVC Frameworks Comparison', 
    author: 'Guybrush Treepwood' 
}, { 
    title: 'Javascript in the year 2014', 
    author: 'Herman Toothrot' 
}, 
{ 
    title: 'Javascript in the year 2013', 
    author: 'Rapp Scallion' 
}]; 

var fuzzy = function(items, key) { 
    // Returns a method that you can use to create your own reusable fuzzy search. 

    return function(query) { 
    var words = query.toLowerCase().split(' '); 

    return items.filter(function(item) { 
     var normalizedTerm = item[key].toLowerCase(); 

     return words.every(function(word) { 
     return (normalizedTerm.indexOf(word) > -1); 
     }); 
    }); 
    }; 
}; 


var searchByTitle = fuzzy(articles, 'title'); 

searchByTitle('javascript 2014') // returns the 1st and 2nd items 

Bueno, espero que esto ayude a alguien por allí.

1

Otra (simple) solución. No distingue entre mayúsculas y minúsculas e ignora el orden de las letras.

Realiza un control para cada letra del término de búsqueda. Si la cadena original contiene esa letra, contará hacia arriba (o hacia abajo si no lo hace). En función de la proporción de coincidencias/longitud de cadena, devolverá verdadero o falso.

String.prototype.fuzzy = function(term, ratio) { 
    var string = this.toLowerCase(); 
    var compare = term.toLowerCase(); 
    var matches = 0; 
    if (string.indexOf(compare) > -1) return true; // covers basic partial matches 
    for (var i = 0; i < compare.length; i++) { 
     string.indexOf(compare[i]) > -1 ? matches += 1 : matches -=1; 
    } 
    return (matches/this.length >= ratio || term == "") 
}; 

Ejemplos:

("Test").fuzzy("st", 0.5) // returns true 
("Test").fuzzy("tes", 0.8) // returns false cause ratio is too low (0.75) 
("Test").fuzzy("stet", 1) // returns true 
("Test").fuzzy("zzzzzest", 0.75) // returns false cause too many alien characters ("z") 
("Test").fuzzy("es", 1) // returns true cause partial match (despite ratio being only 0.5)