How to determine if one string starts with what another ends with

前端 未结 3 1249
一生所求
一生所求 2021-01-29 12:50

I have a list of phrases:

[
  \"according to all known laws of aviation\",
  \"time flies when you\'re having fun...\"
  ...
]

I would like to

3条回答
  •  滥情空心
    2021-01-29 13:05

    It is quite frustrated that I answer here, without anything better than the brute-force... I would really have enjoyed a more clever way to go through it, and still hope someone will.

    But given your application, there a a few optimizations you must add on jojonas' algorithm. You are probably going to perform this check at each keystroke, and since it is an autocomplete, the input may grow in length pretty fast.

    One first optimization is to cut the input to the length of the checked string. Given an input of length 8, and a string to compare of length 3, there is no way the first 5 iterations return a match

    input:   "aaaaaaaa" (8)
    compare:      "aaa" (3)
                   ^- first possible match for compare.startsWith()
    

    This can be quite easily done by initiating our iterator to max(input.length - compare.length, 0).

    A second optimization to this algorithm consist in searching for the first index of the first letter of compare inside the remainder of input. No need to go through every characters, as long as it isn't the first one of compare we can be sure that compare.startsWith will return false. We can then repeat until we find which remainder is correct, once again removing quite a few loops in the whole process.

    const phrases = ["according to all known laws of aviation", "a blessing in disguise", "a bunch", "a dime a dozen", "beat around the bush", "better late than never", "bite the bullet", "break a leg", "call it a day", "cut somebody some slack", "cutting corners", "dead tired", "easy does it", "excuse me", "get it out of my system", "get it out of your system", "get out of hand", "get something out of my system", "get something out of your system", "get your act together"];
    
    
    inp.oninput = e => {
      const overlaps = getOverlaps(inp.value, phrases);
      makeList(overlaps);
      if(logged) console.clear();
    };
    let logged = false;
    inp.oninput(); 
    logged = true;
    
    // "abcde", "def"
    function getOverlaps(input, list) {
      return list.filter(compare => {
        // single logger, just for demo
        const log = (...args) => !logged && compare === "beat around the bush" && console.log.apply(console, args);
    
        // search only in possible area
        let i = Math.max(input.length - compare.length, 0); // 2
        
        log('initial i:', i);
        
        const first_letter = compare[0]; // "d"
        let remain = input.substr(i); // "cde"
        
        log('initial remain:', remain);
        
        while(i < input.length) {
          // jump to first letter
          let index = remain.indexOf(first_letter); // 1
    
          log('in-loop index:', index);
    
          if(index < 0) { // not found
            return false;
          }
          i += index; // 3
          remain = input.substr(i); // "de"
          
          log('in-loop remain:', remain);
          
          if(compare.startsWith(remain)) { // found
            return true; // =>
          }
          
          // wasn't this one, move by one char
          // (will jump to next occurence of first_letter) at next iteration
          i++;
          remain = input.substr(i);
        }
          
      });
    
    }
    
    function makeList(items) {
      list.innerHTML = '';
      items.forEach(e => 
        list.appendChild(
          document.createElement('li')
        ).textContent = e
      );
    }
    body{padding-bottom: 120px}
    
    

    提交回复
    热议问题