Jak mogę zaimplementować wyszukane, rozmyte wyszukiwanie w select2?Jak zaimplementować wysublimowany tekst, np. Wyszukiwanie rozmyte?
przykład wpisanie „sta jav sub” pasowałby „Stackoverflow javascript wzniosły jak”
Jak mogę zaimplementować wyszukane, rozmyte wyszukiwanie w select2?Jak zaimplementować wysublimowany tekst, np. Wyszukiwanie rozmyte?
przykład wpisanie „sta jav sub” pasowałby „Stackoverflow javascript wzniosły jak”
select2 pozwala realizować własne funkcje „dopasowujący” (as seen on their docs), wykorzystując, że niektóre wyrażenia regularne można zrobić coś takiego:
$("#element").select2({
matcher: function(term, text, opt) {
//We call to uppercase to do a case insensitive match
//We replace every group of whitespace characters with a .+
//matching any number of characters
return text.toUpperCase().match(term.toUpperCase().replace(/\s+/g, '.+'));
}
});
funkcja dopasowujący jest wywoływana przed każdym elemencie listy select2 podczas filtrowania/przeszukiwania listy, można wdrożyć jakiejkolwiek Custom Search przy użyciu tego.
Oto alternatywna funkcja dopasowania. http://jsfiddle.net/trevordixon/pXzj3/4/
function match(search, text) {
search = search.toUpperCase();
text = text.toUpperCase();
var j = -1; // remembers position of last found character
// consider each search character one at a time
for (var i = 0; i < search.length; i++) {
var l = search[i];
if (l == ' ') continue; // ignore spaces
j = text.indexOf(l, j+1); // search for character & update position
if (j == -1) return false; // if it's not found, exclude this item
}
return true;
}
Ten jest nieco szybciej (przynajmniej kiedy biegnę this test w Chrome na OS X), co może być ważne, jeśli filtrowanie dużo przedmiotów.
Podoba mi się twoja implementacja, ale twoja nie będzie starała się dopasować do siebie znaków w ciągu wyszukiwania, ej ABS pasowałby do każdego kawalerskiego wschodu słońca, co może, ale nie musi być, czego byś się spodziewał :) – albertein
Czy nie jest to dokładnie to, czego się oczekuje od wyszukiwanie rozmyte? – Kloar
@Kloar On oznacza, że 'ABS' powinien pasować do' Any Bachelor Sunrise', ale 'ABS' powinien pasować tylko, powiedzmy,' ABS Building Co.'' – rvighne
Odpowiedź alberteina nie pasuje do wersji Trevora, ponieważ pierwotna funkcja wykonuje dopasowanie na podstawie znaku, a nie na podstawie słów. Oto prostsze dopasowanie na podstawie znaków:
$("#element").select2({
matcher: function(term, text, opts) {
var pattern = term.replace(/\s+/g, '').split('').join('.*');
text.match(new RegExp(pattern, 'i'))
}
})
var fuzzysearch = function (querystrings, values) {
return !querystrings.some(function (q) {
return !values.some(function (v) {
return v.toLocaleLowerCase().indexOf(q) !== -1;
});
});
}
Przykład szukając tytułu i autora w księgozbiorze http://jsfiddle.net/runjep/r887etnh/2/
Dla alternatywy 9kB która plasuje wynik wyszukiwania: http://kiro.me/projects/fuse.html
ty może potrzebować polyfill dla funkcji "niektóre" https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
var books = [{
id: 1,
title: 'The Great Gatsby',
author: 'F. Scott Fitzgerald'
}, {
id: 2,
title: 'The DaVinci Code',
author: 'Dan Brown'
}, {
id: 3,
title: 'Angels & Demons',
author: 'Dan Brown'
}];
search = function() {
var queryarray = document.getElementById('inp').value.trim().toLowerCase().split(' ');
var res = books.filter(function (b) {
return fs(queryarray, [b.title, b.author]);
});
document.getElementById('res').innerHTML = res.map(function (b) {
return b.title + ' <i> ' + b.author + '</i>';
}).join('<br/> ');
}
fs = function (qs, vals) {
return !qs.some(function (q) {
return !vals.some(function (v) {
return v.toLocaleLowerCase().indexOf(q) !== -1;
});
});
}
<input id="inp" />
<button id="but" onclick="search()">Search</button>
<div id="res"></div>
To jest vanilla javascript i nie wybierz 2 - przepraszam –
function fuzzyMe(term, query) {
var score = 0;
var termLength = term.length;
var queryLength = query.length;
var highlighting = '';
var ti = 0;
// -1 would not work as this would break the calculations of bonus
// points for subsequent character matches. Something like
// Number.MIN_VALUE would be more appropriate, but unfortunately
// Number.MIN_VALUE + 1 equals 1...
var previousMatchingCharacter = -2;
for (var qi = 0; qi < queryLength && ti < termLength; qi++) {
var qc = query.charAt(qi);
var lowerQc = qc.toLowerCase();
for (; ti < termLength; ti++) {
var tc = term.charAt(ti);
if (lowerQc === tc.toLowerCase()) {
score++;
if ((previousMatchingCharacter + 1) === ti) {
score += 2;
}
highlighting += "<em>" + tc + "</em>";
previousMatchingCharacter = ti;
ti++;
break;
} else {
highlighting += tc;
}
}
}
highlighting += term.substring(ti, term.length);
return {
score: score,
term: term,
query: query,
highlightedTerm: highlighting
};
}
Powyższy dba o zamazanie. Następnie można po prostu iteracyjne nad wszystkimi wybierz 2 elementy
$("#element").select2({
matcher: function(term, text, opt) {
return fuzzyMe(term, text).highlightedTerm;
}
});
kredytowe dla kodu rozmytej -: https://github.com/bripkens/fuzzy.js
napisałem kilka, które działa bardzo długo mecz Sublime tekst jest rozmyty. Osiągnięcie tego wymaga kilku rzeczy.
Najpierw dopasuj wszystkie znaki z wzorca w kolejności. Po drugie, partytury są takie, że niektóre dopasowane postacie są warte więcej punktów niż inne.
Wymyśliłem kilka czynników, które należy sprawdzić. Litery lub litery "CamelCase" występujące po separatorze (spacja lub podkreślenie) są warte wielu punktów. Kolejne mecze są warte więcej. Wyniki znalezione w pobliżu początku są warte więcej.
Krytycznie ważną sprawą jest znalezienie najlepiej pasującej postaci. Który niekoniecznie jest pierwszy. Rozważmy fuzzy_match ("tk", "Czarny rycerz"). Istnieją dwa kody K, które można dopasować. Drugi jest wart więcej punktów, ponieważ podąża za przestrzenią.
Kod JavaScript znajduje się poniżej.Jest pewien niuans, który jest opisany bardziej szczegółowo w poście na blogu. Istnieje również interaktywna wersja demonstracyjna. I pełne źródło (w tym demo plus implementacja C++) na GitHub.
// Returns [bool, score, formattedStr]
// bool: true if each character in pattern is found sequentially within str
// score: integer; higher is better match. Value has no intrinsic meaning. Range varies with pattern.
// Can only compare scores with same search pattern.
// formattedStr: input str with matched characters marked in <b> tags. Delete if unwanted.
function fuzzy_match(pattern, str) {
// Score consts
var adjacency_bonus = 5; // bonus for adjacent matches
var separator_bonus = 10; // bonus if match occurs after a separator
var camel_bonus = 10; // bonus if match is uppercase and prev is lower
var leading_letter_penalty = -3; // penalty applied for every letter in str before the first match
var max_leading_letter_penalty = -9; // maximum penalty for leading letters
var unmatched_letter_penalty = -1; // penalty for every letter that doesn't matter
// Loop variables
var score = 0;
var patternIdx = 0;
var patternLength = pattern.length;
var strIdx = 0;
var strLength = str.length;
var prevMatched = false;
var prevLower = false;
var prevSeparator = true; // true so if first letter match gets separator bonus
// Use "best" matched letter if multiple string letters match the pattern
var bestLetter = null;
var bestLower = null;
var bestLetterIdx = null;
var bestLetterScore = 0;
var matchedIndices = [];
// Loop over strings
while (strIdx != strLength) {
var patternChar = patternIdx != patternLength ? pattern.charAt(patternIdx) : null;
var strChar = str.charAt(strIdx);
var patternLower = patternChar != null ? patternChar.toLowerCase() : null;
var strLower = strChar.toLowerCase();
var strUpper = strChar.toUpperCase();
var nextMatch = patternChar && patternLower == strLower;
var rematch = bestLetter && bestLower == strLower;
var advanced = nextMatch && bestLetter;
var patternRepeat = bestLetter && patternChar && bestLower == patternLower;
if (advanced || patternRepeat) {
score += bestLetterScore;
matchedIndices.push(bestLetterIdx);
bestLetter = null;
bestLower = null;
bestLetterIdx = null;
bestLetterScore = 0;
}
if (nextMatch || rematch) {
var newScore = 0;
// Apply penalty for each letter before the first pattern match
// Note: std::max because penalties are negative values. So max is smallest penalty.
if (patternIdx == 0) {
var penalty = Math.max(strIdx * leading_letter_penalty, max_leading_letter_penalty);
score += penalty;
}
// Apply bonus for consecutive bonuses
if (prevMatched)
newScore += adjacency_bonus;
// Apply bonus for matches after a separator
if (prevSeparator)
newScore += separator_bonus;
// Apply bonus across camel case boundaries. Includes "clever" isLetter check.
if (prevLower && strChar == strUpper && strLower != strUpper)
newScore += camel_bonus;
// Update patter index IFF the next pattern letter was matched
if (nextMatch)
++patternIdx;
// Update best letter in str which may be for a "next" letter or a "rematch"
if (newScore >= bestLetterScore) {
// Apply penalty for now skipped letter
if (bestLetter != null)
score += unmatched_letter_penalty;
bestLetter = strChar;
bestLower = bestLetter.toLowerCase();
bestLetterIdx = strIdx;
bestLetterScore = newScore;
}
prevMatched = true;
}
else {
// Append unmatch characters
formattedStr += strChar;
score += unmatched_letter_penalty;
prevMatched = false;
}
// Includes "clever" isLetter check.
prevLower = strChar == strLower && strLower != strUpper;
prevSeparator = strChar == '_' || strChar == ' ';
++strIdx;
}
// Apply score for last match
if (bestLetter) {
score += bestLetterScore;
matchedIndices.push(bestLetterIdx);
}
// Finish out formatted string after last pattern matched
// Build formated string based on matched letters
var formattedStr = "";
var lastIdx = 0;
for (var i = 0; i < matchedIndices.length; ++i) {
var idx = matchedIndices[i];
formattedStr += str.substr(lastIdx, idx - lastIdx) + "<b>" + str.charAt(idx) + "</b>";
lastIdx = idx + 1;
}
formattedStr += str.substr(lastIdx, str.length - lastIdx);
var matched = patternIdx == patternLength;
return [matched, score, formattedStr];
}
miał trudności z nowym Select2, tutaj co pracował
$("#foo").select2({
matcher: matcher
});
function matcher(params, data) {
// return all opts if seachbox is empty
if(!params.term) {
return data;
} else if(data) {
var term = params.term.toUpperCase();
var option = data.text.toUpperCase();
var j = -1; // remembers position of last found character
// consider each search character one at a time
for (var i = 0; i < term.length; i++) {
var l = term[i];
if (l == ' ') continue; // ignore spaces
j = option.indexOf(l, j+1); // search for character & update position
if (j == -1) return false; // if it's not found, exclude this item
}
return data; // return option
}
}
ten zasługuje na więcej przebojów. bardzo przydatna odpowiedź. – r3wt