Як рэалізаваць узнёслы тэкст, як невыразны пошук?

Як я магу рэалізаваць узнёслы-як невыразны пошук па выбор2?

Прыклад, набраўшы «СТО JAV субрахунак» будзе адпавядаць «Stackoverflow яваскрипта ўзвышанага, як»

25

7 адказы

Here's an alternate matching function. 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;
}

Гэта адзін трохі хутчэй (прынамсі, калі я бягу гэты тэст ў Chrome на OS X), што можа быць важна, калі вы фільтрацыі шмат пунктаў.

23
дададзена
Хіба гэта не зусім тое, што чакалася ад невыразнага пошуку?
дададзена аўтар Kloar, крыніца
@Kloar Ён азначае, што ABS павінен адпавядаць Любы Bachelor Sunrise , але ABS павінен адпавядаць толькі, скажам, ABS Building Co.
дададзена аўтар rvighne, крыніца
Я выявіў, што гэта ніколі не шукае першы знак, таму што J ніколі не роўны 0 пры выкананні IndexOf метад. Было б лепш за ўсё выкарыстоўваць J, як ёсць, то пасля таго, як калі ўмова дадаць j ++ для абнаўлення становішча замест ў IndexOf метад.
дададзена аўтар JoeMoe1984, крыніца
Мне падабаецца ваша рэалізацыя, але ў вас не будзе спрабаваць адпавядаць разам сімвалы на радок пошуку, EJ ABS будзе адпавядаць любы Bachelor Sunrise, які можа ці не можа быць тое, што вы чакалі б :)
дададзена аўтар Simon Tillson, крыніца
@rvighne Я думаю, што ABS павінна адпавядаць абодва, але адзін другому матчу павінен атрымаць больш высокі рэйтынг, чым першы
дададзена аўтар Mansiemans, крыніца
Я заснавана маё рашэнне па гэтым пытанні. толькі што абнавіў яго на працу з новай выбор2.
дададзена аўтар AndreiMotinga, крыніца

Выбор2 дазваляе рэалізаваць сваю ўласную «Сличитель» функцыю (, як відаць на іх дакументах ), з дапамогай гэтага і некаторых рэгулярны выраз вы можаце зрабіць нешта накшталт:

$("#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, '.+'));
    }
});

Функцыя ўзгодненасць выклікаецца супраць кожнага ВЫБ.2 элемента спісу пры фільтрацыі/пошуку ў спісе, вы можаце рэалізаваць любы выгляд карыстальніка пошуку з дапамогай гэтага.

11
дададзена
гэта заслугоўвае больш upvotes. вельмі карысны адказ.
дададзена аўтар r3wt, крыніца

Я напісаў некалькі прац, што вельмі доўга недакладнае матч Sublime тэксту. Для дасягнення гэтага патрабуецца некалькі рэчаў.

Па-першае, матч ўсе знакі з шаблону ў паслядоўнасці. Па-другое, ацэнка адпавядае такім чынам, што некаторыя супалі сімвалы стаяць больш ачкоў, чым іншыя.

Я прыдумаў некалькі фактараў, каб праверыць на. «Вярблюджыя» літара ці літары пасля падзельніка (прабел або падкрэслення) каштуе шмат ачкоў. Паслядоўныя матчы каштуе больш. Вынікі знойдзены паблізу пачатку варта больш.

Крытычна важная Хітрасць заключаецца ў тым, каб знайсці найбольш прыдатны сімвал. Але гэта не абавязкова раней усіх. Разгледзім fuzzy_match ( «тк», «Чорны рыцар»). Ёсць два Ks, якія могуць быць супадальнымі. Па-другое, варта больш ачкоў, таму што варта прабел.

JavaScript код ніжэй. Існуе некаторы нюанс, які апісаны больш падрабязна ў блогу. Там таксама інтэрактыўны дэманстрацыйны. І поўны крыніца (уключае ў сябе дэма, а таксама C ++ рэалізацыі) на 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  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) + "" + str.charAt(idx) + "";
            lastIdx = idx + 1;
        }
        formattedStr += str.substr(lastIdx, str.length - lastIdx);
    
        var matched = patternIdx == patternLength;
        return [matched, score, formattedStr];
    }
    
7
дададзена

Адказ albertein не адпавядае версіі Тревора, таму што зыходная функцыя выконвае ўзгадненне на аснове знакаў, а не на словы асновы. Вось больш простае адпаведнасць на аснове знакаў:

$("#element").select2({
  matcher: function(term, text, opts) {
    var pattern = term.replace(/\s+/g, '').split('').join('.*');
    text.match(new RegExp(pattern, 'i'))
  }
})
3
дададзена
var fuzzysearch = function (querystrings, values) {
    return !querystrings.some(function (q) {
        return !values.some(function (v) {
            return v.toLocaleLowerCase().indexOf(q) !== -1;
        });
    });
}

Example searching for title and author in book collection http://jsfiddle.net/runjep/r887etnh/2/

For a 9kb alternative which ranks the search result: http://kiro.me/projects/fuse.html

You may need a polyfill for the 'some' function https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some

<div class="snippet" data-lang="js" data-hide="false"> <div class="snippet-code">

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 + '  ' + b.author + '';
    }).join('
'); } 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>
</div> </div>
1
дададзена
Гэта ваніль яваскрипт і не абраць 2 - прабачце
дададзена аўтар Rune Jeppesen, крыніца
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 += "" + tc + "";
        previousMatchingCharacter = ti;
        ti++;
        break;
      } else {
        highlighting += tc;
      }
    }
  }

  highlighting += term.substring(ti, term.length);

  return {
    score: score,
    term: term,
    query: query,
    highlightedTerm: highlighting
  };
}

Вышэй клапоціцца аб недакладнасці. Тады вы можаце проста перабрацца ўсе элементы выберыце 2

$("#element").select2({
  matcher: function(term, text, opt) {
    return fuzzyMe(term, text).highlightedTerm;
  }
});

Credit for fuzzy code -: https://github.com/bripkens/fuzzy.js

0
дададзена

узніклі цяжкасці з новай выбор2, вось што атрымалася,

 $("#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
  }
}
0
дададзена