2013-06-04 11 views

Odpowiedz

11

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.

+0

ten zasługuje na więcej przebojów. bardzo przydatna odpowiedź. – r3wt

23

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.

+2

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

+11

Czy nie jest to dokładnie to, czego się oczekuje od wyszukiwanie rozmyte? – Kloar

+0

@Kloar On oznacza, że ​​'ABS' powinien pasować do' Any Bachelor Sunrise', ale 'ABS' powinien pasować tylko, powiedzmy,' ABS Building Co.'' – rvighne

3

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')) 
    } 
}) 
1
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>

+0

To jest vanilla javascript i nie wybierz 2 - przepraszam –

0
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

7

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.

  • Blog Post
  • Interactive Demo
  • 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]; 
    } 
    
0

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 
    } 
} 
Powiązane problemy