fuzzy.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package fuzzy
  2. import (
  3. "strings"
  4. )
  5. /*
  6. fuzzy.go
  7. Author: tobychui
  8. This logic is designed to handle fuzzy logic change similar to Google search engine
  9. You can fill in string with fuzzy keywords.
  10. Assume there are two files:
  11. Hello World.txt
  12. Hello World not this.txt
  13. Use fuzzyInput of: World Hello -"not this" .txt
  14. will return "Hello World.txt" as match only
  15. */
  16. type Matcher struct {
  17. caseSensitive bool
  18. matchList []string
  19. excludeList []string
  20. }
  21. func NewFuzzyMatcher(fuzzyInput string, caseSensitive bool) *Matcher {
  22. m, e := buildFuzzyChunks(fuzzyInput, caseSensitive)
  23. return &Matcher{
  24. caseSensitive: caseSensitive,
  25. matchList: m,
  26. excludeList: e,
  27. }
  28. }
  29. func (m *Matcher) Match(filename string) bool {
  30. if !m.caseSensitive {
  31. filename = strings.ToLower(filename)
  32. }
  33. //All keyword in matchList must be satisfied
  34. for _, keyword := range m.matchList {
  35. if !strings.Contains(filename, keyword) {
  36. return false
  37. }
  38. }
  39. //Check if contain exclude words
  40. for _, exclude := range m.excludeList {
  41. if strings.Contains(filename, exclude) {
  42. return false
  43. }
  44. }
  45. return true
  46. }
  47. //Check if a fuzzyKey require precise searching
  48. func buildFuzzyChunks(fuzzyInput string, caseSensitive bool) ([]string, []string) {
  49. includeList := []string{}
  50. excludeList := []string{}
  51. preciseExclude := false //Exclude precise word from buffer
  52. preciseBuffer := []string{}
  53. if !caseSensitive {
  54. fuzzyInput = strings.ToLower(fuzzyInput)
  55. }
  56. fuzzyChunks := strings.Split(fuzzyInput, " ")
  57. for _, thisChunk := range fuzzyChunks {
  58. if len(thisChunk) > 0 && thisChunk[:1] == "\"" && thisChunk[len(thisChunk)-1:] == "\"" {
  59. //This chunk start and end with exact "", just trim the " away
  60. //Example: "asd"
  61. includeList = append(includeList, thisChunk[1:len(thisChunk)-1])
  62. } else if len(thisChunk) > 1 && thisChunk[:1] == "-" && thisChunk[1:2] == "\"" {
  63. // Example: -"asd
  64. preciseExclude = true
  65. preciseBuffer = append(preciseBuffer, thisChunk[2:])
  66. } else if len(thisChunk) > 0 && thisChunk[:1] == "\"" {
  67. //Starting of precise string
  68. //Example (start of): "asd asd"
  69. preciseBuffer = append(preciseBuffer, thisChunk[1:])
  70. } else if len(thisChunk) > 0 && thisChunk[len(thisChunk)-1:] == "\"" {
  71. //End of precise string
  72. //Example (end of): "asd asd"
  73. preciseBuffer = append(preciseBuffer, thisChunk[:len(thisChunk)-1])
  74. tmp := strings.Join(preciseBuffer, " ")
  75. if preciseExclude {
  76. excludeList = append(excludeList, tmp)
  77. } else {
  78. includeList = append(includeList, tmp)
  79. }
  80. //Reset precisebuf
  81. preciseExclude = false
  82. preciseBuffer = []string{}
  83. } else if len(thisChunk) > 0 && thisChunk[:1] == "-" {
  84. //Example: -asd
  85. excludeList = append(excludeList, thisChunk[1:])
  86. } else {
  87. includeList = append(includeList, thisChunk)
  88. }
  89. }
  90. return includeList, excludeList
  91. }