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  }