首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >查询字符串运算符

查询字符串运算符
EN

Stack Overflow用户
提问于 2016-06-27 21:29:39
回答 1查看 977关注 0票数 0

我正在开发一个API,它要求操作符作为值的过滤器。例如&val=true&Amount>33"。我认为内部表示应该是mapstringstruct{操作符字符串,Val [] string },但是标准库似乎不支持它。

是否有任何支持此类查询的外部包?这是一个常见的用例(例如,搜索API),所以我很惊讶在godoc上找不到任何东西。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-28 01:13:55

看来用例并不像我想的那么常见。我实现了一个自定义的“解析器”。希望这不会违反任何RFC。任何补丁都欢迎!

代码语言:javascript
运行
复制
package query

import(
    "net/url"
    "strings"
)


//ParseQueryOp parses the URL-encoded query string and returns a map 
// listing the values specified for each key. ParseQueryOp always returns 
// a non-nil map containing all the valid query parameters found;
// err describes the first decoding error encountered, if any.
// If the query has operators (e.g. &amount>300) it is Add-ed in the map
// with a prefixed key ( {{prefix}}key ).
/*
 e.g. for a query &Amount>300 the operator(">") is returnd
    s := "query &Amount>300"
    q, _ := ParseQueryOp(s, "_op_")
    print(q.Get("_op_Amount")) // prints `>`
    print(q.Get("Amount")) // prints 300
*/
func ParseQueryOp(query, prefix string) (m url.Values, err error){
    m = make(url.Values)

    for query != "" {
        var opKey string
        key := query
        if i := strings.IndexAny(key, "&;"); i >= 0 {
            key, query = key[:i], key[i+1:]
        } else {
            query = ""
        }
        if key == "" {
            continue
        }
        value := ""
        var err1 error
        if i := strings.Index(key, ">="); i >= 0{
            key, value = key[:i], key[i+2:]
            opKey = prefix + key 
            opKey, err1 = url.QueryUnescape(opKey)
            if err1 != nil {
                if err == nil {
                    err = err1
                }
                continue
            }
            m[opKey] = append(m[opKey], ">=")
        }else if i = strings.Index(key, "<="); i >= 0{
            key, value = key[:i], key[i+2:]
            opKey = prefix + key 
            opKey, err1 = url.QueryUnescape(opKey)
            if err1 != nil {
                if err == nil {
                    err = err1
                }
                continue
            }
            m[opKey] = append(m[opKey], "<=")
        }else if i = strings.Index(key, "=");  i >= 0{
            key, value = key[:i], key[i+1:]
        }else if i = strings.Index(key, ">");  i >= 0{
            key, value = key[:i], key[i+1:]
            opKey = prefix + key 
            opKey, err1 = url.QueryUnescape(opKey)
            if err1 != nil {
                if err == nil {
                    err = err1
                }
                continue
            }
            m[opKey] = append(m[opKey], ">")
        }else if i = strings.Index(key, "<"); i >= 0{
            key, value = key[:i], key[i+1:]
            opKey = prefix + key 
            opKey, err1 = url.QueryUnescape(opKey)
            if err1 != nil {
                if err == nil {
                    err = err1
                }
                continue
            }
            m[opKey] = append(m[opKey], "<")
        }

        key, err1 = url.QueryUnescape(key)
        if err1 != nil {
            if err == nil {
                err = err1
            }
            continue
        }
        value, err1 = url.QueryUnescape(value)
        if err1 != nil {
            if err == nil {
                err = err1
            }
            continue
        }
        m[key] = append(m[key], value)
    }
    return m, err
}

和一些测试

代码语言:javascript
运行
复制
package query


import(
    "testing"
    "net/url"
)


type parseTest struct {
    query string
    out   url.Values
}


var parseTests = []parseTest{
    {
        query: "a=1&b=2",
        out:   url.Values{"a": []string{"1"}, "b": []string{"2"}},
    },
    {
        query: "a=1&a=2&a=banana",
        out:   url.Values{"a": []string{"1", "2", "banana"}},
    },
    {
        query: "ascii=%3Ckey%3A+0x90%3E",
        out:   url.Values{"ascii": []string{"<key: 0x90>"}},
    },
    {
        query: "a=1;b=2",
        out:   url.Values{"a": []string{"1"}, "b": []string{"2"}},
    },
    {
        query: "a=1&a=2;a=banana",
        out:   url.Values{"a": []string{"1", "2", "banana"}},
    },
    {
        query: "a=1&b>2",
        out:   url.Values{"a": []string{"1"}, "_op_b": []string{">"}, "b": []string{"2"}},
    },
    {
        query: "a=1&b<2",
        out:   url.Values{"a": []string{"1"}, "_op_b": []string{"<"}, "b": []string{"2"}},
    },
    {
        query: "a=1&b>=2",
        out:   url.Values{"a": []string{"1"}, "_op_b": []string{">="}, "b": []string{"2"}},
    },
    {
        query: "a=1&b<=2",
        out:   url.Values{"a": []string{"1"}, "_op_b": []string{"<="}, "b": []string{"2"}},
    },
}

func TestParseQueryOut(t *testing.T) {
    for i, test := range parseTests {
        form, err := ParseQueryOp(test.query, "_op_")
        if err != nil {
            t.Errorf("test %d: Unexpected error: %v", i, err)
            continue
        }
        if len(form) != len(test.out) {
            t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
        }
        for k, evs := range test.out {
            vs, ok := form[k]
            if !ok {
                t.Errorf("test %d: Missing key %q", i, k)
                continue
            }
            if len(vs) != len(evs) {
                t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
                continue
            }
            for j, ev := range evs {
                if v := vs[j]; v != ev {
                    t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
                }
            }
        }
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38063561

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档