В JavaScript нечеткий поиск
Я работаю над этой фильтрации, где у меня есть около 50-100 элементов списка. И каждый элемент имеет такую разметку:
<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>
Я создал такую разметку, потому что я изначально использовал список.js
Итак, вероятно, вы уже догадались, что я хочу сделать такие поиски:@region: LA @price: 124
и так далее. Проблема в том, что я также хочу отобразить более одного элемента, чтобы выбрать более чем... один:)
Я предполагаю, что это требует нечеткого поиска, но проблема в том, что я не нашел ничего функционального.
любая идея или отправная точка?
/ / edit: поскольку у меня довольно небольшое количество элементов, я хотел бы получить решение на стороне клиента.
7 ответов
Я искал "нечеткий поиск" в javascript, но не нашел решения здесь, поэтому я написал свою собственную функцию, которая делает то, что мне нужно.
алгоритм очень простой: перебираем буквы иглы и проверить, если они происходят в том же порядке в стоге сена:
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;
};
например:
('a haystack with a needle').fuzzy('hay sucks'); // false
('a haystack with a needle').fuzzy('sack hand'); // true
год спустя, список.js получил хороший плагин для нечеткий поиск это работает довольно здорово.
У меня есть небольшая функция, поиск строки в массиве (по крайней мере, для меня это дает лучшие результаты, чем Левенштейн ):
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;
}
и я сделал свой собственный. Он использует выражение и служит больше как доказательство концепции, поскольку она полностью не подвергается стресс-тестированию.
наслаждайтесь javascript нечеткий поиск / нечеткий матч http://unamatasanatarai.github.io/FuzzyMatch/test/index.html
другое (простое) решение. Без учета регистра и игнорирует порядок букв.
он выполняет проверку для каждой буквы поискового термина. Если исходная строка содержит эту букву, она будет рассчитывать вверх (или вниз, если это не так). Основываясь на соотношении совпадений / длины строки, он вернет true или false.
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 == "")
};
примеры:
("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)
Hear-это jsPerf, сравнивающий нечеткий поиск, предложенный tborychowski String.prototype.fuzzy
vs RegExp
где каждый символ разделен .*
Я не был удовлетворен списком.js, поэтому я создал свой собственный. Это, вероятно, не совсем нечеткий поиск, но я не знаю, как его назвать. Я просто хотел, чтобы он соответствовал запросу, независимо от порядка моих слов в запросе.
рассмотрим следующий сценарий:
- существует коллекция статей в памяти
- порядок появления слов запроса не имеет значения (например, "hello world" vs "world hello")
- код должен быть легко читаемый
вот пример:
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
ну, я надеюсь, что это поможет кому-то там.