73 lines
1.2 KiB
Go
73 lines
1.2 KiB
Go
package search
|
|
|
|
import "strings"
|
|
|
|
// Search represents a parsed search query with inclusions and exclusions.
|
|
type Search struct {
|
|
Includes []string
|
|
Excludes []string
|
|
}
|
|
|
|
// ParseSearchString parses a user search query and supports "quoted phrases" and -negations.
|
|
func ParseSearchString(input string) *Search {
|
|
var result = new(Search)
|
|
|
|
var (
|
|
negate bool
|
|
phrase bool
|
|
buf = []rune{}
|
|
commit = func() {
|
|
var text = strings.TrimSpace(string(buf))
|
|
if len(text) == 0 {
|
|
return
|
|
}
|
|
if negate {
|
|
result.Excludes = append(result.Excludes, text)
|
|
negate = false
|
|
} else {
|
|
result.Includes = append(result.Includes, text)
|
|
}
|
|
buf = []rune{}
|
|
}
|
|
)
|
|
|
|
for _, char := range input {
|
|
// Inside a quoted phrase?
|
|
if phrase {
|
|
if char == '"' {
|
|
// End of quoted phrase.
|
|
commit()
|
|
phrase = false
|
|
continue
|
|
}
|
|
buf = append(buf, char)
|
|
continue
|
|
}
|
|
|
|
// Start a quoted phrase?
|
|
if char == '"' {
|
|
phrase = true
|
|
continue
|
|
}
|
|
|
|
// Negation indicator?
|
|
if len(buf) == 0 && char == '-' {
|
|
negate = true
|
|
continue
|
|
}
|
|
|
|
// End of a word?
|
|
if char == ' ' {
|
|
commit()
|
|
continue
|
|
}
|
|
|
|
buf = append(buf, char)
|
|
}
|
|
|
|
// Last word?
|
|
commit()
|
|
|
|
return result
|
|
}
|