【问题标题】:Format a Go string without printing?格式化 Go 字符串而不打印?
【发布时间】:2012-06-22 20:15:19
【问题描述】:

有没有简单的方法在 Go 中格式化字符串而不打印字符串?

我能做到:

bar := "bar"
fmt.Printf("foo: %s", bar)

但我希望返回格式化的字符串而不是打印出来,以便进一步操作它。

我也可以这样做:

s := "foo: " + bar

但是当格式字符串很复杂时,这变得难以阅读,当一个或多个部分不是字符串并且必须首先转换时,这变得很麻烦,比如

i := 25
s := "foo: " + strconv.Itoa(i)

有没有更简单的方法来做到这一点?

【问题讨论】:

    标签: string go formatting string-formatting


    【解决方案1】:
    推荐的答案 Go Language

    Sprintf 就是你要找的东西。

    示例

    fmt.Sprintf("foo: %s", bar)
    

    您还可以在 Errors example 中看到它作为“围棋之旅”的一部分。

    return fmt.Sprintf("at %v, %s", e.When, e.What)
    

    【讨论】:

    • % 后面的字母重要吗?可以是 %y 和 %q 吗?或 %y 和 %y
    • 字母很重要,它被称为动词,基本上它让 Sprintf 知道变量是什么类型,所以如果它收到 65 并且动词是 %d 它将打印数字 65 但如果动词是 %c 它将打印字符'A'。见:golang.org/pkg/fmt/#hdr-Printing
    • 为什么叫Sprintf? S代表字符串,f代表格式?如果函数不输出到屏幕,那么 print 是函数名称的一部分,这很奇怪。这让我困惑了一段时间......
    • 你救了我谢谢UUUUUUUUUU
    【解决方案2】:

    1。简单字符串

    对于“简单”字符串(通常适合一行),最简单的解决方案是使用fmt.Sprintf() 和朋友(fmt.Sprint()fmt.Sprintln())。这些类似于没有起始 S 字母的函数,但这些 Sxxx() 变体将结果作为 string 返回,而不是将它们打印到标准输出。

    例如:

    s := fmt.Sprintf("Hi, my name is %s and I'm %d years old.", "Bob", 23)
    

    变量s将被初始化为值:

    Hi, my name is Bob and I'm 23 years old.
    

    提示:如果您只想连接不同类型的值,您可能不需要自动使用Sprintf()(需要格式字符串),因为Sprint() 正是这样做的。看这个例子:

    i := 23
    s := fmt.Sprint("[age:", i, "]") // s will be "[age:23]"
    

    对于仅连接strings,您还可以使用strings.Join(),您可以在其中指定自定义分隔符string(放置在要连接的字符串之间)。

    Go Playground 上试试这些。

    2。复杂的字符串(文档)

    如果您尝试创建的字符串更复杂(例如,多行电子邮件),fmt.Sprintf() 的可读性和效率会降低(尤其是如果您必须多次这样做)。

    为此,标准库提供了包text/templatehtml/template。这些包实现了用于生成文本输出的数据驱动模板。 html/template 用于生成对代码注入安全的 HTML 输出。它提供了与包text/template 相同的接口,并且只要输出为HTML,就应该使用它而不是text/template

    使用template 包基本上需要您以string 值的形式提供一个静态模板(它可能源自一个文件,在这种情况下您只提供文件名),其中可能包含静态文本,以及引擎处理模板并生成输出时处理和执行的操作。

    您可以提供静态模板中包含/替换的参数,这些参数可以控制输出生成过程。此类参数的典型形式是 structs 和 map 值,它们可以嵌套。

    示例:

    例如,假设您要生成如下所示的电子邮件:

    Hi [name]!
    
    Your account is ready, your user name is: [user-name]
    
    You have the following roles assigned:
    [role#1], [role#2], ... [role#n]
    

    要生成这样的电子邮件正文,您可以使用以下静态模板:

    const emailTmpl = `Hi {{.Name}}!
    
    Your account is ready, your user name is: {{.UserName}}
    
    You have the following roles assigned:
    {{range $i, $r := .Roles}}{{if $i}}, {{end}}{{.}}{{end}}
    `
    

    并提供这样的数据来执行它:

    data := map[string]interface{}{
        "Name":     "Bob",
        "UserName": "bob92",
        "Roles":    []string{"dbteam", "uiteam", "tester"},
    }
    

    通常模板的输出被写入io.Writer,因此如果您希望结果为string,请创建并写入bytes.Buffer(实现io.Writer)。执行模板,得到结果为string

    t := template.Must(template.New("email").Parse(emailTmpl))
    buf := &bytes.Buffer{}
    if err := t.Execute(buf, data); err != nil {
        panic(err)
    }
    s := buf.String()
    

    这将产生预期的输出:

    Hi Bob!
    
    Your account is ready, your user name is: bob92
    
    You have the following roles assigned:
    dbteam, uiteam, tester
    

    Go Playground 上试用。

    另请注意,从 Go 1.10 开始,bytes.Buffer 可以使用更新、更快、更专业的替代方案,即:strings.Builder。用法很相似:

    builder := &strings.Builder{}
    if err := t.Execute(builder, data); err != nil {
        panic(err)
    }
    s := builder.String()
    

    Go Playground 上试试这个。

    注意:如果您提供os.Stdout 作为目标(也实现了io.Writer),您也可以显示模板执行的结果:

    t := template.Must(template.New("email").Parse(emailTmpl))
    if err := t.Execute(os.Stdout, data); err != nil {
        panic(err)
    }
    

    这会将结果直接写入os.Stdout。在Go Playground 上试试这个。

    【讨论】:

      【解决方案3】:

      尝试使用Sprintf();它不会打印输出,而是将其保存以备将来使用。 看看这个。

      package main
      
      import "fmt"
      
      func main() {
          
          address := "NYC"
      
          fmt.Sprintf("I live in %v", address)
      
      }
      

      当你运行这段代码时,它不会输出任何东西。但是,一旦您将 Sprintf() 分配给一个单独的变量,它就可以用于将来的目的。

      package main
      
      import "fmt"
      
      func main() {
          
          address := "NYC"
      
          fmt.Sprintf("I live in %v", address)
      
          var city = fmt.Sprintf("lives in %v", address)
          fmt.Println("Michael",city)
      
      }
      

      【讨论】:

        【解决方案4】:

        在您的情况下,您需要使用 Sprintf() 作为格式字符串。

        func Sprintf(format string, a ...interface{}) string

        Sprintf 根据格式说明符格式化并返回结果字符串。

        s := fmt.Sprintf("Good Morning, This is %s and I'm living here from last %d years ", "John", 20)

        您的输出将是:

        早上好,我是约翰,过去 20 年我一直住在这里。

        【讨论】:

          【解决方案5】:

          我们可以通过define new TypeFormat 支持自定义一个新的字符串类型。

          package main
          
          import (
              "fmt"
              "text/template"
              "strings"
          )
          
          type String string
          func (s String) Format(data map[string]interface{}) (out string, err error) {
              t := template.Must(template.New("").Parse(string(s)))
              builder := &strings.Builder{}
              if err = t.Execute(builder, data); err != nil {
                  return
              }
              out = builder.String()
              return
          }
          
          
          func main() {
              const tmpl = `Hi {{.Name}}!  {{range $i, $r := .Roles}}{{if $i}}, {{end}}{{.}}{{end}}`
              data := map[string]interface{}{
                  "Name":     "Bob",
                  "Roles":    []string{"dbteam", "uiteam", "tester"},
              }
          
              s ,_:= String(tmpl).Format(data)
              fmt.Println(s)
          }
          

          注意:{{.}}{{range $i, $r := .Roles}} {{.}} {{end}} 中代表{{$r}}

          【讨论】:

            【解决方案6】:

            我已经创建了用于从模板格式化字符串的 go 项目(它允许以 C# 或 Python 样式格式化字符串,这只是非常简单情况的第一个版本),你可以在这里找到它https://github.com/Wissance/stringFormatter

            它的工作方式如下:

            
            func TestStrFormat(t *testing.T) {
                strFormatResult, err := Format("Hello i am {0}, my age is {1} and i am waiting for {2}, because i am {0}!",
                                          "Michael Ushakov (Evillord666)", "34", "\"Great Success\"")
                assert.Nil(t, err)
                assert.Equal(t, "Hello i am Michael Ushakov (Evillord666), my age is 34 and i am waiting for \"Great Success\", because i am Michael Ushakov (Evillord666)!", strFormatResult)
            
                strFormatResult, err = Format("We are wondering if these values would be replaced : {5}, {4}, {0}", "one", "two", "three")
                assert.Nil(t, err)
                assert.Equal(t, "We are wondering if these values would be replaced : {5}, {4}, one", strFormatResult)
            
                strFormatResult, err = Format("No args ... : {0}, {1}, {2}")
                assert.Nil(t, err)
                assert.Equal(t, "No args ... : {0}, {1}, {2}", strFormatResult)
            }
            
            func TestStrFormatComplex(t *testing.T) {
                strFormatResult, err := FormatComplex("Hello {user} what are you doing here {app} ?", map[string]string{"user":"vpupkin", "app":"mn_console"})
                assert.Nil(t, err)
                assert.Equal(t, "Hello vpupkin what are you doing here mn_console ?", strFormatResult)
            }
            
            

            【讨论】:

              【解决方案7】:

              我来到这个页面专门寻找一种格式化错误字符串的方法。因此,如果有人需要帮助,您可以使用 fmt.Errorf() 函数。

              方法签名是func Errorf(format string, a ...interface{}) error。 它将格式化的字符串作为满足error 接口的值返回。

              您可以在文档中查找更多详细信息 - https://golang.org/pkg/fmt/#Errorf

              【讨论】:

                【解决方案8】:

                除了使用template.New,您可以使用new 内置函数 template.Template:

                package main
                
                import (
                   "strings"
                   "text/template"
                )
                
                func format(s string, v interface{}) string {
                   t, b := new(template.Template), new(strings.Builder)
                   template.Must(t.Parse(s)).Execute(b, v)
                   return b.String()
                }
                
                func main() {
                   bar := "bar"
                   println(format("foo: {{.}}", bar))
                   i := 25
                   println(format("foo: {{.}}", i))
                }
                

                【讨论】:

                  【解决方案9】:

                  fmt.SprintF 函数返回一个字符串,您可以像使用fmt.PrintF 一样格式化字符串

                  【讨论】:

                    猜你喜欢
                    • 2016-06-21
                    • 1970-01-01
                    • 2019-05-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-08-29
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多