douan8473
douan8473
采纳率100%
2016-03-14 20:51 阅读 72
已采纳

在Go中解析简单的复选框组

I'm parsing a form in Go and I frequently find groups of checkboxes which need to be processed into text like so:

[ ] Foo
[x] Bar
[ ] Baz
[x] Bat

where the output should be a comma-separated list "BarText, BatText" corresponding to the checked items, or "None" if none of the items are checked. What is a good way to handle this situation? Repeating the logic each time seems like a bad idea.

In the spirit of YAGNI there's no need to handle possible future changes like translations into other languages (actually this example is highly unlikely to be useful in the present context).

Efficiency is unimportant for this application.

Edit: code looks like this (source):

func handleCheckboxesForm(w http.ResponseWriter, r *http.Request) {
    b := func(name string) string { // helper function for boolean values in the form
        return r.FormValue(name) == "on"
    }

    text := "Header stuff here"

    mytext := ""
    if b("nfpa-alk") {
        mytext += ", alkaline"
    }
    if b("nfpa-acid") {
        mytext += ", acid"
    }
    if b("nfpa-w") {
        mytext += ", reacts violently with water"
    }
    if b("nfpa-alk") || b("nfpa-acid") || b("nfpa-w") {
        text += mytext[2:] + "
"
    } else {
        text += "none
"
    }

    // lots of other checkbox groups here

    // do stuff with text
}
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

2条回答 默认 最新

  • 已采纳
    dtvfshi5248 dtvfshi5248 2016-03-14 21:31

    There are many repeating code in yours which can be optimized out.

    Your code must contain at least the following "fragments":

    1. The mappings from entry name to entry text, which can be stored in a map, e.g.

      var mappings = map[string]string {
          "Foo": "Foo text",
          "Bar": "Bar text",
          "Baz": "Baz text",
          "Bat": "Bat text",
          // ... other mappings
      }
      
    2. And the list of keys belonging to a group, which can be stored in a slice, e.g.

      var group1 = []string{"Foo", "Bar", "Baz", "Bat"}
      

    Once you defined these, you can have a helper method which handles a group:

    func handleGroup(r *http.Request, group []string) (res string) {
        for _, v := range group {
            if r.FormValue(v) == "on" {
                res := ", " + mappings[v]
            }
        }
        if res == "" {
            return "none
    "
        }
        return res[2:] + "
    "
    }
    

    That's all. After this your handler can be this simple:

    func checkboxHandler(w http.ResponseWriter, r *http.Request) {
        // Handle group1:
        res1 := handleGroup(r, group1)
    
        // Handle group2:
        res2 := handleGroup(r, group2)
    }
    

    Notes:

    It wasn't your requirement, but this solution handles translations very easily: each translation can have its own mappings map, and that's all. Nothing else needs to be changed.

    Performance also wasn't your concern, but appending strings isn't very efficient this way. If performance is at least a little concern, you can improve it without adding complexity by utilizing bytes.Buffer:

    func handleGroup(r *http.Request, group []string) string {
        buf := &bytes.Buffer{}
        for _, v := range group {
            if r.FormValue(v) == "on" {
                buf.WriteString(", ")
                buf.WriteString(mappings[v])
            }
        }
        if buf.Len() == 0 {
            return "none
    "
        }
        buf.WriteString("
    ")
        return string(buf.Bytes()[2:])
    }
    
    点赞 评论 复制链接分享
  • dox19458 dox19458 2016-03-14 21:10

    This will store the form values into an array. Then, it will iterate the array into a string with appending "," at the end of each name. Then, it will put very last ", " (2 bytes) if it's longer than 2, otherwise, print "None"

    func(w http.ResponseWriter, r *http.Request) {
        r.ParseMultipartForm(0)
        arr := []string{}
        if r.FormValue("Foo") {
            arr = append(arr, "Foo")
        }
        if r.FormValue("Bar") {
            arr = append(arr, "Bar")
        }
        if r.FormValue("Baz") {
            arr = append(arr, "Baz")
        }
        if r.FormValue("Bat") {
            arr = append(arr, "Bat")
        }
        out := ""
        for _, title := range arr {
            out += title +", "
        }
        if len(out) > 2 {
            out := out[0: len(out)-2]   
        } else {
            out = "None"
        }
    
        fmt.Println(out)
    }
    

    If you want to iterate,

    for k, vs:= range r.Form {   
      for _, v:= range vs{
         fmt.Println(k, v)
      }
    }
    
    点赞 评论 复制链接分享

相关推荐