Example #1
0
// 配备并重新组合查询语句, 给出QCnd对象
func (qb *QWBuilder) evalQCnd(fld string) *QCnd {
	for _, rule := range qb.Rules {
		if rule.Regex.MatchString(fld) {
			z.DebugPrintf("fld [%s] match regex [%s]\n", fld, rule.Regex.String())
			groups := rule.Regex.FindStringSubmatch(fld)
			for _, grp := range groups {
				z.DebugPrintf("    g_%s\n", grp)
			}
			extractStr := z.Trim(findMatchStr(rule.Seg, groups))
			// 生成QCnd
			qc := new(QCnd)
			qc.Key = rule.Key
			qc.Origin = fld
			qc.Plain = extractStr
			qc.Type = rule.Type
			switch qc.Type {
			case String:
				qc.Value = extractStr
			case Regex:
				qc.Value = regexp.MustCompile(extractStr)
			case IntRegion, LongRegion, DateRegion:
				qc.Value = z.MakeRegion(extractStr)
			case StringEnum:
				senum := extractStr[1 : len(extractStr)-1]
				qc.Value = z.SplitIgnoreBlank(senum, ",")
			case IntEnum:
				ienum := extractStr[1 : len(extractStr)-1]
				iarray := make([]int, 0, 5)
				for _, ie := range z.SplitIgnoreBlank(ienum, ",") {
					ione, _ := strconv.Atoi(ie)
					iarray = append(iarray, ione)
				}
				qc.Value = iarray
			case Json:
				jmap := new(map[string]interface{})
				jerr := z.JsonFromString(extractStr, jmap)
				if jerr != nil {
					qc.Value = jmap
				}
			default:
				// unsupport
				qc.Value = nil
			}
			return qc
		}
	}
	z.DebugPrintf("fld [%s] miss match\n", fld)
	return nil
}
Example #2
0
func Test_QWord_Each(t *testing.T) {
	qb := query.QWordBuilder(strings.NewReader(`
		$user  : ^(@)(.*)$
			${2} = String
		$test :: S
		    $(2) = StringEnum
	`))
	qword := qb.Parse("@zozoh ,     S(abc,hha, erer, jdgg gdg)")
	qword.Each(func(index int, qc *query.QCnd, prevIsAnd bool) {
		z.DebugPrintf("no.%d prevIsAnd.%v \n", index, prevIsAnd)
		z.DebugPrintln(qc.String())
	})
}
Example #3
0
func Test_QWord_Region(t *testing.T) {
	qb := query.QWordBuilder(strings.NewReader(`
		$ct  :: C
			${2} = IntRegion
		$st  :: S
			${2} = IntRegion
		$usr : ^(@)([a-zA-Z]+)$
			${2} = String
	`))
	qword := qb.Parse("C[10,15], S(12,) , @pw")
	qword.Each(func(index int, qc *query.QCnd, prevIsAnd bool) {
		z.DebugPrintf("no.%d prevIsAnd.%v \n", index, prevIsAnd)
		z.DebugPrintln(qc.String())
	})
	qc := qword.Get("usr")
	if qc == nil {
		t.Error("can't find qcnd by key")
	}
}
Example #4
0
// 提取查询语句与连接符
func (qb *QWBuilder) extractFldsAndSeps(kwd string) (isGOr, isGAnd bool, flds []string, seps []byte) {
	// 判断全局参数 (先强制认为 'xxx:')
	// FIXME 后面改成正则匹配, 可以多加空格
	isGOr = strings.HasPrefix(kwd, qb.GOr+":")
	isGAnd = strings.HasPrefix(kwd, qb.GAnd+":")
	if isGOr || isGAnd {
		kwd = kwd[strings.Index(kwd, ":")+1:]
	}
	// 分割查询字符串
	flds = make([]string, 0, 5)
	seps = make([]byte, 0, 5)
	// FIXME 这个地方需要在好好想想
	// 保证一个特殊情况下的正确性, 比如或是" "与是"," kwd中有类似"xxx , yyy"这样的语句,需要把处理
	// 这个特例是一搬在" "当做或的情况下
	if z.IsInStrings(qb.SepOr, " ") {
		for _, sAnd := range qb.SepAnd {
			ss := " " + sAnd + " "
			kwd = strings.Replace(kwd, ss, sAnd, -1)
		}
	}
	// 开始解析
	kszie := len(kwd)
	fld := z.StringBuilder()
	for i := 0; i < kszie; i++ {
		c := kwd[i]
		z.DebugPrintf("extract kwd %3d -> [%s]\n", i, string(c))
		// 如果是引用
		if pos := z.IndexOfStrings(qb.QuoteBegin, string(c)); pos > 0 {
			// 这里面的空格啥的就不会被跳过了, 会一直取到引用结束, 逃逸字符会调整一下
			for i++; i < kszie; i++ {
				c = kwd[i]
				if string(c) == qb.QuoteEnd[pos] {
					break
				} else if c == '\\' {
					// FIXME 这里没有做防守
					i++
					fld.Append(kwd[i])
				} else {
					fld.Append(c)
				}
			}
			continue
		}
		// 如果是括弧
		if z.IsInStrings(qb.BracketBegin, string(c)) {
			fld.Append(c)
			for i++; i < kszie; i++ {
				c = kwd[i]
				fld.Append(c)
				if z.IsInStrings(qb.BracketEnd, string(c)) {
					break
				}
			}
			continue
		}
		// 如果是分隔符
		if z.IsInStrings(qb.SepAnd, string(c)) || z.IsInStrings(qb.SepOr, string(c)) {
			cfld := z.Trim(fld.String())
			if len(cfld) > 0 {
				flds = append(flds, cfld)
				seps = append(seps, c)
				fld = z.StringBuilder()
			}
			continue
		}
		// 没什么特殊情况,那就加入到sb
		fld.Append(c)
	}
	// 加入最后一个条件
	lfld := z.Trim(fld.String())
	if len(lfld) > 0 {
		flds = append(flds, lfld)
	}
	// 打印一下
	if z.IsDebugOn() && len(flds) > 0 {
		z.DebugPrintf("kwd : %s\n", kwd)
		for _, f := range flds {
			z.DebugPrintf("fld : %s\n", f)
		}
		for _, s := range seps {
			z.DebugPrintf("sep : '%s'\n", string(s))
		}
	}
	return isGOr, isGAnd, flds, seps
}
Example #5
0
// 读取解析规则, 传入一个实现了io.Reader的对象即可
func (qb *QWBuilder) LoadRules(reader io.Reader) *QWBuilder {
	bufreader := bufio.NewReader(reader)
	var line string
	var lnum int
	var err error
	var rules []*QWordRule = make([]*QWordRule, 0)
	for true {
		line, err = bufreader.ReadString('\n')
		if err == io.EOF {
			err = nil
			break
		} else if err != nil {
			break
		}
		lnum++
		z.DebugPrintf("rule %2d : %s", lnum, line)
		// 忽略空行与注释行
		line = strings.TrimSpace(line)
		if z.IsBlank(line) || strings.HasPrefix(line, "#") {
			continue
		}
		// 解析行信息
		if strings.HasPrefix(line, "$") {
			qwRule := new(QWordRule)
			// 获得key
			var fpos int = strings.Index(line, ":")
			if fpos < 0 {
				err = errors.New(fmt.Sprintf("invalid rule line %d : %s", lnum, line))
				break
			}
			qwRule.Key = strings.TrimSpace(line[1:fpos])

			// 获得regex
			var expr string
			if line[fpos+1] == ':' {
				// 简要模式
				expr = "^(" + strings.TrimSpace(line[fpos+2:]) + ")(.*)$"
			} else {
				// 普通模式
				expr = strings.TrimSpace(line[fpos+1:])
			}
			regex, regerr := regexp.Compile(expr)
			if regerr != nil {
				err = regerr
				break
			}
			qwRule.Regex = regex

			// 读取下一行,必须存在哟
			line, err = bufreader.ReadString('\n')
			if err == io.EOF {
				err = errors.New(fmt.Sprintf("rule line(%d) miss next line", lnum))
				break
			} else if err != nil {
				break
			}
			lnum++
			z.DebugPrintf("rule %2d : %s", lnum, line)
			line = strings.TrimSpace(line)
			spos := strings.Index(line, "=")
			if z.IsBlank(line) || !strings.HasPrefix(line, "$") || spos < 0 {
				err = errors.New(fmt.Sprintf("invalid rule line %d : %s", lnum, line))
				break
			}
			// 获得seg
			qwRule.Seg = z.Trim(line[:spos])
			// 获得type
			qcType, qcterr := QCType(strings.TrimSpace(line[spos+1:]))
			if qcterr != nil {
				err = qcterr
				break
			}
			qwRule.Type = qcType
			// 加入到rules
			rules = append(rules, qwRule)
		}
	}
	// 是否有错误
	if err != nil {
		panic(err)
	}
	qb.Rules = rules
	return qb
}