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

huangapple go评论87阅读模式
英文:

Parsing simple groups of checkboxes in Go

问题

我正在解析一个Go表单,并经常遇到需要将复选框组处理成文本的情况,如下所示:

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

输出应该是一个逗号分隔的列表"BarText, BatText",对应于选中的项目,如果没有选中任何项目,则为"None"。如何处理这种情况?每次重复逻辑似乎不是一个好主意。

根据YAGNI原则,没有必要处理可能的未来变化,比如翻译成其他语言(实际上,在当前情况下,这个例子极不可能有用)。

效率对于这个应用程序来说不重要。

编辑:代码如下(来源):

func handleCheckboxesForm(w http.ResponseWriter, r *http.Request) {
    b := func(name string) string { // 表单中布尔值的辅助函数
        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:] + "\n"
    } else {
        text += "none\n"
    }

    // 这里有很多其他的复选框组

    // 处理文本
}
英文:

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:] + "\n"
	} else {
		text += "none\n"
	}

	// lots of other checkbox groups here

	// do stuff with text
}

答案1

得分: 1

你的代码中有很多重复的部分可以进行优化。

你的代码至少应包含以下“片段”:

  1. 从条目名称到条目文本的映射,可以存储在一个映射中,例如:

     var mappings = map[string]string {
         "Foo": "Foo text",
         "Bar": "Bar text",
         "Baz": "Baz text",
         "Bat": "Bat text",
         // ... 其他映射
     }
    
  2. 属于一个组的键的列表,可以存储在一个切片中,例如:

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

定义了这些之后,你可以有一个处理组的辅助方法:

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\n"
    }
    return res[2:] + "\n"
}

就是这样。在此之后,你的处理程序可以变得很简单:

func checkboxHandler(w http.ResponseWriter, r *http.Request) {
    // 处理 group1:
    res1 := handleGroup(r, group1)

    // 处理 group2:
    res2 := handleGroup(r, group2)
}

注意:

这不是你的要求,但这个解决方案可以很容易地处理翻译:每个翻译可以有自己的 mappings 映射,其他不需要改变。

性能也不是你关心的问题,但是这种方式的字符串拼接效率不高。如果性能至少有一点关注,你可以通过利用 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\n"
    }
    buf.WriteString("\n")
    return string(buf.Bytes()[2:])
}
英文:

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\n"
    }
    return res[2:] + "\n"
}

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\n"
    }
    buf.WriteString("\n")
    return string(buf.Bytes()[2:])
}

答案2

得分: 0

这将把表单的值存储到一个数组中。
然后,它将迭代数组,将每个名称的末尾添加","。
如果长度超过2,则在最后添加", "(2个字节),否则打印"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)
}

如果要进行迭代

for k, vs := range r.Form {
    for _, v := range vs {
        fmt.Println(k, v)
    }
}
英文:

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)
  }
}

huangapple
  • 本文由 发表于 2016年3月15日 04:51:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/35997842.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定