a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
82 lines
2.0 KiB
Go
82 lines
2.0 KiB
Go
package search
|
|
|
|
import (
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
// Tokenize splits a string into searchable tokens by:
|
|
// - camelCase boundaries (getUserById → [get, user, by, id])
|
|
// - snake_case boundaries (get_user_by_id → [get, user, by, id])
|
|
// - path separators (internal/auth/token.go → [internal, auth, token, go])
|
|
// - dot separators (UserService.FindUser → [user, service, find, user])
|
|
//
|
|
// All tokens are lowercased. Tokens shorter than 2 characters are dropped.
|
|
func Tokenize(s string) []string {
|
|
var tokens []string
|
|
var current []rune
|
|
|
|
flush := func() {
|
|
if len(current) >= 2 {
|
|
tokens = append(tokens, strings.ToLower(string(current)))
|
|
}
|
|
current = current[:0]
|
|
}
|
|
|
|
runes := []rune(s)
|
|
for i, r := range runes {
|
|
switch {
|
|
case r == '_' || r == '/' || r == '.' || r == ':' || r == '-' || r == ' ':
|
|
flush()
|
|
case unicode.IsUpper(r):
|
|
if len(current) > 0 {
|
|
prev := current[len(current)-1]
|
|
// camelCase: lowercase followed by uppercase → split
|
|
if unicode.IsLower(prev) {
|
|
flush()
|
|
}
|
|
// ALLCAPS followed by uppercase+lowercase → split before the last uppercase
|
|
// e.g. HTMLParser: H-T-M-L-P → flush "HTML" before "P"
|
|
if unicode.IsUpper(prev) && i+1 < len(runes) && unicode.IsLower(runes[i+1]) {
|
|
flush()
|
|
}
|
|
}
|
|
current = append(current, r)
|
|
case unicode.IsLetter(r) || unicode.IsDigit(r):
|
|
current = append(current, r)
|
|
default:
|
|
flush()
|
|
}
|
|
}
|
|
flush()
|
|
|
|
if tokens == nil {
|
|
tokens = []string{}
|
|
}
|
|
return tokens
|
|
}
|
|
|
|
// TokenizeQuery tokenizes a search query, keeping all tokens (including short ones
|
|
// that might be meaningful like "go" or "js").
|
|
func TokenizeQuery(s string) []string {
|
|
var tokens []string
|
|
var current []rune
|
|
|
|
flush := func() {
|
|
if len(current) > 0 {
|
|
tokens = append(tokens, strings.ToLower(string(current)))
|
|
}
|
|
current = current[:0]
|
|
}
|
|
|
|
for _, r := range s {
|
|
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
|
|
current = append(current, r)
|
|
} else {
|
|
flush()
|
|
}
|
|
}
|
|
flush()
|
|
return tokens
|
|
}
|