SamKr
11/2/2018 - 9:45 AM

Wildcard Matching

Checks for string comparison using wildcards

// https://bitbucket.org/hasullivan/fast-wildcard-matching/src/c07bea26631b31baa014ab928a806ed8f6eba9f5/FastWildcardMatching/WildcardMatch.cs?at=master&fileviewer=file-view-default

// ReSharper disable SwitchStatementMissingSomeCases
// ReSharper disable ForCanBeConvertedToForeach
using System.Collections.Generic;
using System.Linq;

public static class WildcardMatch
{
  public static bool EqualsWildcard(this string text, string wildcardString)
  {
      var isLike = true;
      byte matchCase = 0;
      char[] reversedFilter;
      char[] reversedWord;
      var currentPatternStartIndex = 0;
      var lastCheckedHeadIndex = 0;
      var lastCheckedTailIndex = 0;
      var reversedWordIndex = 0;
      var reversedPatterns = new List<char[]>();
  
      if (text == null || wildcardString == null)
      {
          return false;
      }
  
      var word = text.ToCharArray();
      var filter = wildcardString.ToCharArray();
  
      if (filter.Any(t => t == '?')) matchCase += 1;
  
      if (filter.Any(t => t == '*')) matchCase += 2;
  
      if ((matchCase == 0 || matchCase == 1) && word.Length != filter.Length)
      {
          return false;
      }
  
      switch (matchCase)
      {
          case 0:
              isLike = (text == wildcardString);
              break;
  
          case 1:
              for (var i = 0; i < text.Length; i++)
              {
                  if ((word[i] != filter[i]) && filter[i] != '?')
                  {
                      isLike = false;
                  }
              }
              break;
  
          case 2:
              for (var i = 0; i < filter.Length; i++)
              {
                  if (filter[i] != '*')
                  {
                      if (filter[i] != word[i])
                      {
                          return false;
                      }
                  }
                  else
                  {
                      lastCheckedHeadIndex = i;
                      break;
                  }
              }
  
              for (var i = 0; i < filter.Length; i++)
              {
                  if (filter[filter.Length - 1 - i] != '*')
                  {
                      if (filter[filter.Length - 1 - i] != word[word.Length - 1 - i])
                      {
                          return false;
                      }
  
                  }
                  else
                  {
                      lastCheckedTailIndex = i;
                      break;
                  }
              }
  
              reversedWord = new char[word.Length - lastCheckedHeadIndex - lastCheckedTailIndex];
              reversedFilter = new char[filter.Length - lastCheckedHeadIndex - lastCheckedTailIndex];
  
              for (var i = 0; i < reversedWord.Length; i++)
              {
                  reversedWord[i] = word[word.Length - (i + 1) - lastCheckedTailIndex];
              }
  
              for (var i = 0; i < reversedFilter.Length; i++)
              {
                  reversedFilter[i] = filter[filter.Length - (i + 1) - lastCheckedTailIndex];
              }
  
              for (var i = 0; i < reversedFilter.Length; i++)
              {
                  if (reversedFilter[i] != '*') continue;
  
                  if (i - currentPatternStartIndex > 0)
                  {
                      var pattern = new char[i - currentPatternStartIndex];
                      for (var j = 0; j < pattern.Length; j++)
                      {
                          pattern[j] = reversedFilter[currentPatternStartIndex + j];
                      }
                      reversedPatterns.Add(pattern);
                  }
                  currentPatternStartIndex = i + 1;
              }
  
              for (var i = 0; i < reversedPatterns.Count; i++)
              {
                  for (var j = 0; j < reversedPatterns[i].Length; j++)
                  {
                      if (reversedWordIndex > reversedWord.Length - 1)
                      {
                          return false;
                      }
  
                      if (reversedPatterns[i][j] != reversedWord[reversedWordIndex + j])
                      {
                          reversedWordIndex += 1;
                          j = -1;
                      }
                      else
                      {
                          if (j == reversedPatterns[i].Length - 1)
                          {
                              reversedWordIndex = reversedWordIndex + reversedPatterns[i].Length;
                          }
                      }
                  }
              }
              break;
  
          case 3:
              for (var i = 0; i < filter.Length; i++)
              {
                  if (filter[i] != '*')
                  {
                      if (filter[i] != word[i] && filter[i] != '?')
                      {
                          return false;
                      }
                  }
                  else
                  {
                      lastCheckedHeadIndex = i;
                      break;
                  }
              }
  
              for (var i = 0; i < filter.Length; i++)
              {
                  if (filter[filter.Length - 1 - i] != '*')
                  {
                      if (filter[filter.Length - 1 - i] != word[word.Length - 1 - i] && filter[filter.Length - 1 - i] != '?')
                      {
                          return false;
                      }
  
                  }
                  else
                  {
                      lastCheckedTailIndex = i;
                      break;
                  }
              }
  
              reversedWord = new char[word.Length - lastCheckedHeadIndex - lastCheckedTailIndex];
              reversedFilter = new char[filter.Length - lastCheckedHeadIndex - lastCheckedTailIndex];
  
              for (var i = 0; i < reversedWord.Length; i++)
              {
                  reversedWord[i] = word[word.Length - (i + 1) - lastCheckedTailIndex];
              }
  
              for (var i = 0; i < reversedFilter.Length; i++)
              {
                  reversedFilter[i] = filter[filter.Length - (i + 1) - lastCheckedTailIndex];
              }
  
              for (var i = 0; i < reversedFilter.Length; i++)
              {
                  if (reversedFilter[i] != '*') continue;
  
                  if (i - currentPatternStartIndex > 0)
                  {
                      var pattern = new char[i - currentPatternStartIndex];
                      for (var j = 0; j < pattern.Length; j++)
                      {
                          pattern[j] = reversedFilter[currentPatternStartIndex + j];
                      }
                      reversedPatterns.Add(pattern);
                  }
  
                  currentPatternStartIndex = i + 1;
              }
  
              for (var i = 0; i < reversedPatterns.Count; i++)
              {
                  for (var j = 0; j < reversedPatterns[i].Length; j++)
                  {
                      if (reversedWordIndex > reversedWord.Length - 1)
                      {
                          return false;
                      }
  
                      if (reversedPatterns[i][j] != '?' && reversedPatterns[i][j] != reversedWord[reversedWordIndex + j])
                      {
                          reversedWordIndex += 1;
                          j = -1;
                      }
                      else
                      {
                          if (j == reversedPatterns[i].Length - 1)
                          {
                              reversedWordIndex = reversedWordIndex + reversedPatterns[i].Length;
                          }
                      }
                  }
              }
  
              break;
      }
  
      return isLike;
  }
}