duanmangxie7131 2014-11-12 23:11
浏览 456
已采纳

使用golang模板打印以逗号和“或”分隔的列表

It is already elsewhere discussed on stackoverflow that you can print a list separated by comma, as follows:

{{ range $index, $element := .TeamMembers}}
    {{if $index}},{{end}}
    {{$element.Name}}
{{end}}

Is there an easy solution for when you need a list separator that is different for the last item, to include an "or":

{name}, {name}, {name}, or {name}

This is to allow, for example, creation of formatted sentences such as:

The members of this team are Bob, Jane, and Mike.

Any template code I can workout ends up extremely verbose and complicated.

  • 写回答

2条回答 默认 最新

  • douyonglang4845 2014-11-13 05:26
    关注

    Export a function to your template.

    text/template, like some other template systems, doesn't try be good for programming in directly; it just provides a better way to stitch your data and functions with your markup, and you need to write other presentational code when it's insufficient. You can write a yourapp/template module that exports a version of New() that calls Funcs() to add the common functions you use.

    (You might find uses for a lot more functions than just these; Django, for example, offers lots of builtins for pluralization, formatting, i18n, etc., and folks still often extend the set.)

    package main // package mytemplate
    
    import (
        "fmt"
        "os"
        "strings"
        "text/template"
    )
    
    func conjoin(conj string, items []string) string {
        if len(items) == 0 {
            return ""
        }
        if len(items) == 1 {
            return items[0]
        }
        if len(items) == 2 { // "a and b" not "a, and b"
            return items[0] + " " + conj + " " + items[1]
        }
    
        sep := ", "
        pieces := []string{items[0]}
        for _, item := range items[1 : len(items)-1] {
            pieces = append(pieces, sep, item)
        }
        pieces = append(pieces, sep, conj, " ", items[len(items)-1])
    
        return strings.Join(pieces, "")
    }
    
    // if you use some funcs everywhere have some package export a Template constructor that makes them available, like this:
    
    var commonFuncs = template.FuncMap{
        "andlist": func(items []string) string { return conjoin("and", items) },
        "orlist":  func(items []string) string { return conjoin("or", items) },
    }
    
    func New(name string) *template.Template {
        return template.New(name).Funcs(commonFuncs)
    }
    
    func main() {
        // test conjoin
        fmt.Println(conjoin("or", []string{}))
        fmt.Println(conjoin("or", []string{"Bob"}))
        fmt.Println(conjoin("or", []string{"Bob", "Mike"}))
        fmt.Println(conjoin("or", []string{"Bob", "Mike", "Harold"}))
    
        people := []string{"Bob", "Mike", "Harold", "Academy Award nominee William H. Macy"}
        data := map[string]interface{}{"people": people}
        tmpl, err := New("myyy template").Parse("{{ orlist .people }} / {{ andlist .people }}")
        if err != nil {
            fmt.Println("sadness:", err.Error())
            return
        }
        err = tmpl.Execute(os.Stdout, data)
        if err != nil {
            fmt.Println("sadness:", err.Error())
            return
        }
    }
    

    Here's a variation that also exports "conjoin", and an "isLast" function you can use in a kind of verbose construction to do some arbitrary thing differently in the last go through the loop.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制
  • ¥20 usb设备兼容性问题
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?