格式化Go字符串而不打印?

在Go中是否有一种简单的方法来格式化字符串而不打印字符串?

我可以:

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

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

我还可以这样做:

s := "foo: " + bar

但是,当格式字符串很复杂时,就很难读取,当一个或多个部分不是字符串,必须先转换时,就会很麻烦,比如

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

有更简单的方法吗?

333672 次浏览

Sprintf是你要找的。

例子

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

你也可以在错误的例子中看到它的使用,作为“围棋之旅”的一部分。

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

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]"

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

去操场上试试这些。

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 1.10以来,bytes.Buffer有了一个更新、更快、更专门的替代方案,即:strings.Builder。用法非常相似:

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

去操场上试试这个。

注意:如果你提供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。在去操场上试试这个。

在本例中,您需要使用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年了。

fmt.SprintF函数返回一个字符串,你可以用与fmt.PrintF相同的方式格式化字符串

我已经创建了一个从模板(它允许在 c#或Python风格格式化字符串)通过性能测试,它比fmt更好。Sprintf的字符串格式化项目,你可以在这里找到它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)
}


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

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

你可以在文档- https://golang.org/pkg/fmt/#Errorf中查找更多细节。

try using 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)


}

而不是使用template.New,你可以使用内置的new with 模板。模板: < / p >

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