You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

162 lines
3.2 KiB

  1. package service
  2. import (
  3. "bytes"
  4. "fmt"
  5. "hash/fnv"
  6. "sort"
  7. "strings"
  8. "sync"
  9. goahocorasick "github.com/anknown/ahocorasick"
  10. )
  11. func SundaySearch(text string, pattern string) bool {
  12. textRunes := []rune(text)
  13. patternRunes := []rune(pattern)
  14. if len(patternRunes) == 0 {
  15. return true
  16. }
  17. if len(patternRunes) > len(textRunes) {
  18. return false
  19. }
  20. // 计算偏移表
  21. offset := make(map[rune]int)
  22. for i, c := range patternRunes {
  23. offset[c] = len(patternRunes) - i
  24. }
  25. // 文本串长度和模式串长度
  26. n, m := len(textRunes), len(patternRunes)
  27. // 主循环,i表示当前对齐的文本串位置
  28. for i := 0; i <= n-m; {
  29. // 检查子串
  30. j := 0
  31. for j < m && textRunes[i+j] == patternRunes[j] {
  32. j++
  33. }
  34. // 如果完全匹配,返回匹配位置
  35. if j == m {
  36. return true
  37. }
  38. // 如果还有剩余字符,则检查下一位字符在偏移表中的值
  39. if i+m < n {
  40. next := textRunes[i+m]
  41. if val, ok := offset[next]; ok {
  42. i += val // 存在于偏移表中,进行跳跃
  43. } else {
  44. i += len(pattern) + 1 // 不存在于偏移表中,跳过整个模式串长度
  45. }
  46. } else {
  47. break
  48. }
  49. }
  50. return false // 如果没有找到匹配,返回-1
  51. }
  52. func RemoveDuplicate(s []string) []string {
  53. result := make([]string, 0, len(s))
  54. temp := map[string]struct{}{}
  55. for _, item := range s {
  56. if _, ok := temp[item]; !ok {
  57. temp[item] = struct{}{}
  58. result = append(result, item)
  59. }
  60. }
  61. return result
  62. }
  63. func InitAc(dict []string) *goahocorasick.Machine {
  64. m := new(goahocorasick.Machine)
  65. runes := readRunes(dict)
  66. if err := m.Build(runes); err != nil {
  67. fmt.Println(err)
  68. return nil
  69. }
  70. return m
  71. }
  72. var acCache sync.Map
  73. func acKey(dict []string) string {
  74. if len(dict) == 0 {
  75. return ""
  76. }
  77. normalized := make([]string, 0, len(dict))
  78. for _, w := range dict {
  79. w = strings.ToLower(strings.TrimSpace(w))
  80. if w != "" {
  81. normalized = append(normalized, w)
  82. }
  83. }
  84. if len(normalized) == 0 {
  85. return ""
  86. }
  87. sort.Strings(normalized)
  88. hasher := fnv.New64a()
  89. for _, w := range normalized {
  90. hasher.Write([]byte{0})
  91. hasher.Write([]byte(w))
  92. }
  93. return fmt.Sprintf("%x", hasher.Sum64())
  94. }
  95. func getOrBuildAC(dict []string) *goahocorasick.Machine {
  96. key := acKey(dict)
  97. if key == "" {
  98. return nil
  99. }
  100. if v, ok := acCache.Load(key); ok {
  101. if m, ok2 := v.(*goahocorasick.Machine); ok2 {
  102. return m
  103. }
  104. }
  105. m := InitAc(dict)
  106. if m == nil {
  107. return nil
  108. }
  109. if actual, loaded := acCache.LoadOrStore(key, m); loaded {
  110. if cached, ok := actual.(*goahocorasick.Machine); ok {
  111. return cached
  112. }
  113. }
  114. return m
  115. }
  116. func readRunes(dict []string) [][]rune {
  117. var runes [][]rune
  118. for _, word := range dict {
  119. word = strings.ToLower(word)
  120. l := bytes.TrimSpace([]byte(word))
  121. runes = append(runes, bytes.Runes(l))
  122. }
  123. return runes
  124. }
  125. func AcSearch(findText string, dict []string, stopImmediately bool) (bool, []string) {
  126. if len(dict) == 0 {
  127. return false, nil
  128. }
  129. if len(findText) == 0 {
  130. return false, nil
  131. }
  132. m := getOrBuildAC(dict)
  133. if m == nil {
  134. return false, nil
  135. }
  136. hits := m.MultiPatternSearch([]rune(findText), stopImmediately)
  137. if len(hits) > 0 {
  138. words := make([]string, 0)
  139. for _, hit := range hits {
  140. words = append(words, string(hit.Word))
  141. }
  142. return true, words
  143. }
  144. return false, nil
  145. }