github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/runes/runes.go (about) 1 // Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . 2 3 package runes 4 5 // ContainsAnyWordRunes 直接使用rune检查字符串是否包含任一单词 6 func ContainsAnyWordRunes(s string, words [][]rune, isCaseInsensitive bool) bool { 7 var allRunes = []rune(s) 8 if len(allRunes) == 0 || len(words) == 0 { 9 return false 10 } 11 12 var lastRune rune // last searching rune in s 13 var lastIndex = -2 // -2: not started, -1: not found, >=0: rune index 14 for _, wordRunes := range words { 15 if len(wordRunes) == 0 { 16 continue 17 } 18 19 if lastIndex > -2 && lastRune == wordRunes[0] { 20 if lastIndex >= 0 { 21 result, _ := ContainsWordRunes(allRunes[lastIndex:], wordRunes, isCaseInsensitive) 22 if result { 23 return true 24 } 25 } 26 continue 27 } else { 28 result, firstIndex := ContainsWordRunes(allRunes, wordRunes, isCaseInsensitive) 29 lastIndex = firstIndex 30 if result { 31 return true 32 } 33 } 34 lastRune = wordRunes[0] 35 } 36 return false 37 } 38 39 // ContainsAnyWord 检查字符串是否包含任一单词 40 func ContainsAnyWord(s string, words []string, isCaseInsensitive bool) bool { 41 var allRunes = []rune(s) 42 if len(allRunes) == 0 || len(words) == 0 { 43 return false 44 } 45 46 var lastRune rune // last searching rune in s 47 var lastIndex = -2 // -2: not started, -1: not found, >=0: rune index 48 for _, word := range words { 49 var wordRunes = []rune(word) 50 if len(wordRunes) == 0 { 51 continue 52 } 53 54 if lastIndex > -2 && lastRune == wordRunes[0] { 55 if lastIndex >= 0 { 56 result, _ := ContainsWordRunes(allRunes[lastIndex:], wordRunes, isCaseInsensitive) 57 if result { 58 return true 59 } 60 } 61 continue 62 } else { 63 result, firstIndex := ContainsWordRunes(allRunes, wordRunes, isCaseInsensitive) 64 lastIndex = firstIndex 65 if result { 66 return true 67 } 68 } 69 lastRune = wordRunes[0] 70 } 71 return false 72 } 73 74 // ContainsAllWords 检查字符串是否包含所有单词 75 func ContainsAllWords(s string, words []string, isCaseInsensitive bool) bool { 76 var allRunes = []rune(s) 77 if len(allRunes) == 0 || len(words) == 0 { 78 return false 79 } 80 81 for _, word := range words { 82 if result, _ := ContainsWordRunes(allRunes, []rune(word), isCaseInsensitive); !result { 83 return false 84 } 85 } 86 return true 87 } 88 89 // ContainsWordRunes 检查字符列表是否包含某个单词子字符列表 90 func ContainsWordRunes(allRunes []rune, subRunes []rune, isCaseInsensitive bool) (result bool, firstIndex int) { 91 firstIndex = -1 92 93 var l = len(subRunes) 94 if l == 0 { 95 return false, 0 96 } 97 98 var al = len(allRunes) 99 100 for index, r := range allRunes { 101 if EqualRune(r, subRunes[0], isCaseInsensitive) && (index == 0 || !isChar(allRunes[index-1]) /**boundary check **/) { 102 if firstIndex < 0 { 103 firstIndex = index 104 } 105 106 var found = true 107 if l > 1 { 108 for i := 1; i < l; i++ { 109 var subIndex = index + i 110 if subIndex > al-1 || !EqualRune(allRunes[subIndex], subRunes[i], isCaseInsensitive) { 111 found = false 112 break 113 } 114 } 115 } 116 117 // check after charset 118 if found && (al <= index+l || !isChar(allRunes[index+l]) /**boundary check **/) { 119 return true, firstIndex 120 } 121 } 122 } 123 124 return false, firstIndex 125 } 126 127 // ContainsSubRunes 检查字符列表是否包含某个子子字符列表 128 // 与 ContainsWordRunes 不同,这里不需要检查边界符号 129 func ContainsSubRunes(allRunes []rune, subRunes []rune, isCaseInsensitive bool) bool { 130 var l = len(subRunes) 131 if l == 0 { 132 return false 133 } 134 135 var al = len(allRunes) 136 137 for index, r := range allRunes { 138 if EqualRune(r, subRunes[0], isCaseInsensitive) { 139 var found = true 140 if l > 1 { 141 for i := 1; i < l; i++ { 142 var subIndex = index + i 143 if subIndex > al-1 || !EqualRune(allRunes[subIndex], subRunes[i], isCaseInsensitive) { 144 found = false 145 break 146 } 147 } 148 } 149 150 // check after charset 151 if found { 152 return true 153 } 154 } 155 } 156 157 return false 158 } 159 160 // EqualRune 判断两个rune是否相同 161 func EqualRune(r1 rune, r2 rune, isCaseInsensitive bool) bool { 162 const d = 'a' - 'A' 163 return r1 == r2 || 164 (isCaseInsensitive && r1 >= 'a' && r1 <= 'z' && r1-r2 == d) || 165 (isCaseInsensitive && r1 >= 'A' && r1 <= 'Z' && r1-r2 == -d) 166 } 167 168 func isChar(r rune) bool { 169 return r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' 170 }