Bootstrap

golang规则引擎-expr

官网地址

https://expr-lang.org/docs/getting-started

简介

Expr是一个语法解析器,可以便捷的解析一些语法并获取结果。

例子

map + function

map: 是将数组中的每个进行加过处理,然后返回一个数组
function:类似于例子中的Format函数,是可以在expr中执行的。

package main

import (
	"fmt"
	"github.com/expr-lang/expr"
	"time"
)

type Env struct {
	Posts []Post `expr:"posts"`
}

func (Env) Format(t time.Time) string { // Methods defined on the struct become functions.
	return t.Format("2006-01-02 15:04:05")
}

type Post struct {
	Body string
	Date time.Time
}

func main() {
	// .Data标识当前元素的Data字段的值
	code := `map(posts, Format(.Date) + ": " + .Body)`

	program, err := expr.Compile(code, expr.Env(Env{})) // Pass the struct as an environment.
	if err != nil {
		panic(err)
	}

	env := Env{
		Posts: []Post{
			{"Oh My God!", time.Now()},
			{"How you doin?", time.Now()},
			{"Could I be wearing any more clothes?", time.Now()},
		},
	}

	output, err := expr.Run(program, env)
	if err != nil {
		panic(err)
	}

	fmt.Print(output)
}

output:

[2021-08-06 09:08:08: Oh My God! 2021-08-06 09:08:08: How you doin? 2021-08-06 09:08:08: Could I be wearing any more clothes?]

any + matches + slice

any: 匹配任意一个满足,就输出true,否则为false
matches: 熟悉的正则匹配
slice[:]: 指定数组的子序列,
假设当前我们的数据结构是这样的

type InferData struct {
	Name    string
	Address string
	History []*History
}

type History struct {
	User      string
	Assistant string
}

匹配规则就可以这样写, 用来匹配历史记录中,是否有一个历史记录的用户名包含"刘德华"

any(History, {.User matches '^.*刘德华.*$'})

指定数组的子序列进行匹配。

any(History[0:1], {.User matches '^.*刘德华.*$'})

多条件匹配,除了andor&&,还支持 oror ||notor !

`any(History, {.User matches '^.*刘德华.*$'}) && Name == '珠穆朗玛峰'`
;