evalostic

package module
v1.10.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2022 License: MIT Imports: 8 Imported by: 0

README

GoDoc Build Status Go Report Card

go-evalostic

go-evalostic can be used to evaluate logical string conditions with Golang.

Usage

The usage of go-evalotic is very simple. Just define a list of conditions and pass it to the constructor. You will then have access to a matcher that can apply all conditions to a specific string and returns the indices of all matching conditions.

Condition Syntax

All strings in a condition have to be quoted (they will be unquoted with strconv.Unquote()). Multiple strings can be concatenated with the keywords AND, OR and parentheses ( ). Strings or subconditions can be negated with NOT. Per default, strings are case sensitive. To make a string case insensitive, add a i after quotes.

Example (Case Sensitive): "foo" AND NOT ("bar" OR "baz")

Example (Case Insensitive): "foo"i AND NOT ("bar"i OR "baz"i)

Code Example

e, err := evalostic.New([]string{
    `"foo" OR "bar"`,
    `NOT "foo" AND ("bar" OR "baz")`,
    // add more conditions here
})
if err != nil {
    panic(err)
}
e.Match("foo") // returns [0]
e.Match("bar") // returns [0, 1]
e.Match("foobar") // returns [0]
e.Match("baz") // returns [1]
e.Match("qux") // returns nil

Documentation

Overview

Example (ExtractStrings)
es := func(cond string) {
	root, err := parseCondition(cond)
	if err != nil {
		panic(err)
	}
	str, positive := extractStrings(root)
	fmt.Printf("----- %s -----\n", cond)
	fmt.Printf("strings: %+v\n", str)
	fmt.Printf("positive: %t\n", positive)
}
es(`"foo"`)
es(`"foo" AND "bar"`)
es(`"foo" OR "bar"`)
es(`NOT "foo"`)
es(`"foo" AND NOT "bar"`)
es(`"foo" OR NOT "bar"`)
es(`NOT ("foo" OR "bar")`)
es(`NOT ("foo" AND "bar")`)
es(`NOT ("foo" OR NOT "bar")`)
es(`NOT ("foo" AND NOT "bar")`)
Output:

----- "foo" -----
strings: [foo]
positive: true
----- "foo" AND "bar" -----
strings: [foo bar]
positive: true
----- "foo" OR "bar" -----
strings: [foo bar]
positive: true
----- NOT "foo" -----
strings: [foo]
positive: false
----- "foo" AND NOT "bar" -----
strings: [foo bar]
positive: true
----- "foo" OR NOT "bar" -----
strings: [foo bar]
positive: false
----- NOT ("foo" OR "bar") -----
strings: [foo bar]
positive: false
----- NOT ("foo" AND "bar") -----
strings: [foo bar]
positive: false
----- NOT ("foo" OR NOT "bar") -----
strings: [foo bar]
positive: true
----- NOT ("foo" AND NOT "bar") -----
strings: [foo bar]
positive: false
Example (Parse)
p := func(cond string) {
	t, err := tokenize(cond)
	if err != nil {
		panic(err)
	}
	root, err := parse(t)
	if err != nil {
		panic(err)
	}
	fmt.Printf("----- %s -----\n", cond)
	fmt.Println(root.String())
}
p(`"foo"`)
p(`"foo" AND "bar"`)
p(`"foo" AND NOT "bar"`)
p(`"foo" AND NOT ("bar" OR "baz")`)
p(`("foo" OR "bar") AND ("bar" OR "baz") AND ("baaz" OR "qux")`)
Output:

----- "foo" -----
nodeVAL{"foo"}
----- "foo" AND "bar" -----
nodeAND{nodeVAL{"foo"},nodeVAL{"bar"}}
----- "foo" AND NOT "bar" -----
nodeAND{nodeVAL{"foo"},nodeNOT{nodeVAL{"bar"}}}
----- "foo" AND NOT ("bar" OR "baz") -----
nodeAND{nodeVAL{"foo"},nodeNOT{nodeOR{nodeVAL{"bar"},nodeVAL{"baz"}}}}
----- ("foo" OR "bar") AND ("bar" OR "baz") AND ("baaz" OR "qux") -----
nodeAND{nodeAND{nodeOR{nodeVAL{"foo"},nodeVAL{"bar"}},nodeOR{nodeVAL{"bar"},nodeVAL{"baz"}}},nodeOR{nodeVAL{"baaz"},nodeVAL{"qux"}}}
Example (Parse_multi)
p := func(cond string) {
	t, err := tokenize(cond)
	if err != nil {
		panic(err)
	}
	root, err := parse(t)
	if err != nil {
		panic(err)
	}
	fmt.Printf("----- %s -----\n", cond)
	fmt.Println(root.Condition())
}
p(`NOT "foo" OR NOT "bar" OR NOT "baz" OR NOT "qux"`)
p(`"qux" AND "foo" OR "bar" AND "baz"`)
p(`"qux" OR "foo" AND "bar" OR "baz"`)
Output:

----- NOT "foo" OR NOT "bar" OR NOT "baz" OR NOT "qux" -----
((NOT "foo" OR NOT "bar") OR (NOT "baz" OR NOT "qux"))
----- "qux" AND "foo" OR "bar" AND "baz" -----
(("qux" AND "foo") OR ("bar" AND "baz"))
----- "qux" OR "foo" AND "bar" OR "baz" -----
(("qux" OR ("foo" AND "bar")) OR "baz")
Example (RandomCondition)
rand.Seed(0)
fmt.Println(randomCondition(3))
fmt.Println(randomCondition(3))
fmt.Println(randomCondition(3))
fmt.Println(randomCondition(3))
fmt.Println(randomCondition(3))
fmt.Println(randomCondition(3))
Output:

"ERA9rI2cvTK4UHom"i
NOT "QvymkzADm"
("HwxmE4tL20SrW"i AND (NOT "U86R7wIBbUt9RwI9U" OR "aWsz0l"i) AND "egogMR6spJPZHaPT0w4"i)
"nRPswXn0i6jt3PARUDb0oU"
NOT "aT3LnXs1oH7gq"i
(NOT ("K4k"i OR NOT "UcTwCQmwFJPivbFQtOWS") OR NOT "8bmfKkaauLI"i)
Example (RandomString)
rand.Seed(0)
fmt.Println(randomString(10))
fmt.Println(randomString(10))
Output:

mUNERA9rI2
cvTK4UHomc
Example (Tokenize)
tk := func(cond string) {
	tokens, err := tokenize(cond)
	if err != nil {
		panic(err)
	}
	fmt.Printf("----- %s -----\n", cond)
	for _, token := range tokens {
		fmt.Println(token.String())
	}
}
tk(`"foo"`)
tk(`"foo" AND "bar"`)
tk(`"foo" AND ("bar" OR "baz")`)
tk(`"foo" AND ("bar" OR NOT "baz")`)
tk(`"escaped quote: \""`)
Output:

----- "foo" -----
nodeVAL ( foo ) at pos 1
----- "foo" AND "bar" -----
nodeVAL ( foo ) at pos 1
nodeAND ( AND ) at pos 7
nodeVAL ( bar ) at pos 11
----- "foo" AND ("bar" OR "baz") -----
nodeVAL ( foo ) at pos 1
nodeAND ( AND ) at pos 7
LPAR ( ( ) at pos 11
nodeVAL ( bar ) at pos 12
nodeOR ( OR ) at pos 18
nodeVAL ( baz ) at pos 21
RPAR ( ) ) at pos 26
----- "foo" AND ("bar" OR NOT "baz") -----
nodeVAL ( foo ) at pos 1
nodeAND ( AND ) at pos 7
LPAR ( ( ) at pos 11
nodeVAL ( bar ) at pos 12
nodeOR ( OR ) at pos 18
nodeNOT ( NOT ) at pos 21
nodeVAL ( baz ) at pos 25
RPAR ( ) ) at pos 30
----- "escaped quote: \"" -----
nodeVAL ( escaped quote: " ) at pos 1

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Evalostic

type Evalostic struct {
	// contains filtered or unexported fields
}

Evalostic is a matcher that can apply multiple conditions on a string with some performance optimizations. The biggest optimization is that only conditions that contain at least one keyword of the string will be checked, these strings will be filtered with the Aho-Corasick algorithm. The only exception are negative conditions (see comment of: Negatives() function).

func New

func New(conditions []string) (*Evalostic, error)

New builds a new Evalostic matcher that compiles all conditions to one big rule set that can be applied to strings.

func (*Evalostic) ExportElasticSearchQuery added in v1.0.2

func (e *Evalostic) ExportElasticSearchQuery(wildcardField string) string

ExportElasticSearchQuery exports the compiled query into an ElasticSearch query, e.g. `"foo" OR "baz"` will be compiled to {"bool":{"should":[{"wildcard":{"raw":{"case_insensitive":false,"value":"*foo*"}}},{"wildcard":{"raw":{"case_insensitive":false,"value":"*bar*"}}}]}}

func (*Evalostic) ExportElasticSearchQueryMap added in v1.0.3

func (e *Evalostic) ExportElasticSearchQueryMap(wildcardField string) map[string]interface{}

ExportElasticSearchQuery exports the compiled query into an ElasticSearch query, e.g. `"foo" OR "baz"` will be compiled to {"bool":{"should":[{"wildcard":{"raw":{"case_insensitive":false,"value":"foo"}}},{"wildcard":{"raw":{"case_insensitive":false,"value":"bar"}}}]}}

func (*Evalostic) Match

func (e *Evalostic) Match(s string) (matchingConditions []int)

Match returns all indices of conditions that match the provided string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL