2012-02-09 24 views
7

Sto lavorando a questa cosa di filtro in cui ho circa 50-100 voci di elenco. E ogni articoli hanno markup come questo:Ricerca fuzzy JavaScript

<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> 

ho creato markup come questo perché inizialmente usato List.js

Quindi, probabilmente già indovinato, quello che voglio è fare ricerche in questo modo: @region: LA @price: 124 e così via . Il problema è che voglio anche visualizzare più di un elemento, al fine di selezionare più di ... uno :)

Presumo che questo abbia bisogno di ricerca fuzzy, ma il problema è che non ho trovato nulla di funzionale.

Qualche idea o punto di partenza?

// modifica: perché ho una piccola quantità di articoli, vorrei una soluzione lato client.

+1

Check this out: http://code.google.com/p/yeti-witch/ - potrebbe essere di aiuto. – techfoobar

+0

Controlla anche se il tuo requisito ti permette di spostare la parte di ricerca fuzzy sul lato server (con AJAX) - In tal caso, farlo usando solr sarebbe la cosa più facile da fare. Oltre al fatto che puoi cercare tra migliaia di oggetti in pochissimo tempo. http://lucene.apache.org/solr/ – techfoobar

+0

Techfoobar: grazie, ma yeti sembra essere più simile a java che javascript. Non riesco a capire come usarlo sul mio codice esistente. Inoltre, anche Solr sembra essere java. Ho bisogno di qualcosa di lato client o PHP. –

risposta

5

Un anno dopo, List.js ho un bel plugin per fuzzy search che funziona molto bene.

+2

fa la ricerca ma non è proprio la" ricerca fuzzy ". ad esempio nella loro demo" fuzzy "query:" bruwo "non trova" Guybrush Threepwood "... – tborychowski

+0

È possibile specificare la modalità di ricerca della sfocatura. È possibile digitare bruw e" Guybrush Treepwood "viene visualizzato. È quando si ottengono due caratteri da la seconda parola che il risultato è filtrato. – user393274

1

ho un po 'di funzione, la ricerca di una stringa in un array (almeno per me che produce risultati migliori rispetto 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

Perché stai chiamando 'arr [i] .toLowerCase(). IndexOf (test [ r] .toLowerCase(). split ("*") ' più volte ?! – Metalstorm

20

ero alla ricerca di "ricerca fuzzy" in javascript, ma rifugio' Ho trovato una soluzione qui, quindi ho scritto la mia funzione che fa ciò di cui ho bisogno.

L'algoritmo è molto semplice: passante attraverso lettere aghi e verificare se si verificano nello stesso ordine in pagliaio:

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; 
}; 

es:

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

questa dovrebbe essere la risposta accettata! –

0

non ero Sono soddisfatto di list.js, quindi ho creato il mio. Probabilmente non è esattamente una ricerca fuzzy, ma non so come chiamarla. Volevo semplicemente che corrispondesse a una query senza riguardo all'ordine delle mie parole nella query.

Si consideri il seguente scenario:

  • esiste una raccolta di articoli in memoria
  • ordine delle parole di query aspetto non importa (per esempio"Ciao mondo" vs "ciao mondo")
  • Il codice deve essere facilmente leggibile

Ecco un esempio:

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 

Beh, spero che questo aiuta qualcuno là fuori.

1

Un'altra (semplice) soluzione. Non sensibile al maiuscolo/minuscolo e ignora l'ordine delle lettere.

Esegue un controllo per ogni lettera del termine di ricerca. Se la stringa originale contiene quella lettera, conterà (o diminuirà se non lo fa). In base al rapporto tra le corrispondenze/lunghezza della stringa restituirà vero 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 == "") 
}; 

Esempi:

("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)