格式化一个Go字符串而不打印出来?

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

Format a Go string without printing?

问题

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

我可以这样做:

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

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

我也可以这样做:

s := "foo: " + bar

但是当格式化字符串复杂时,阅读起来变得困难,并且当其中一个或多个部分不是字符串并且需要先转换时,这种方法变得繁琐,例如

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

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

英文:

Is there a simple way to format a string in Go without printing the string?

I can do:

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

But I want the formatted string returned rather than printed so I can manipulate it further.

I could also do something like:

s := "foo: " + bar

But this becomes difficult to read when the format string is complex, and cumbersome when one or many of the parts aren't strings and have to be converted first, like

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

Is there a simpler way to do this?

答案1

得分: 679

Sprintf 是你要找的东西。

示例

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

你还可以在 Errors example 中看到它的使用,作为 "A Tour of Go." 的一部分。

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

Sprintf is what you are looking for.

Example

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

You can also see it in use in the Errors example as part of "A Tour of Go."

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

答案2

得分: 262

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将是"[age:23]"

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

Go Playground上尝试一下。

2. 复杂字符串(文档)

如果您要创建的字符串更复杂(例如多行电子邮件消息),那么fmt.Sprintf()的可读性和效率就会降低(特别是如果您需要多次执行此操作)。

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

使用template包基本上要求您提供一个静态模板,以string值的形式提供(如果来自文件,则只提供文件名),该模板可以包含静态文本和在引擎处理模板并生成输出时处理和执行的操作。

您可以提供参数,这些参数将包含/替换静态模板中的内容,并且可以控制输出生成过程。此类参数的典型形式是嵌套的structmap值。

示例:

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

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上尝试一下。

英文:

1. Simple strings

For "simple" strings (typically what fits into a line) the simplest solution is using fmt.Sprintf() and friends (fmt.Sprint(), fmt.Sprintln()). These are analogous to the functions without the starter S letter, but these Sxxx() variants return the result as a string instead of printing them to the standard output.

For example:

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

The variable s will be initialized with the value:

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

Tip: If you just want to concatenate values of different types, you may not automatically need to use Sprintf() (which requires a format string) as Sprint() does exactly this. See this example:

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

For concatenating only strings, you may also use strings.Join() where you can specify a custom separator string (to be placed between the strings to join).

Try these on the Go Playground.

2. Complex strings (documents)

If the string you're trying to create is more complex (e.g. a multi-line email message), fmt.Sprintf() becomes less readable and less efficient (especially if you have to do this many times).

For this the standard library provides the packages text/template and html/template. These packages implement data-driven templates for generating textual output. html/template is for generating HTML output safe against code injection. It provides the same interface as package text/template and should be used instead of text/template whenever the output is HTML.

Using the template packages basically requires you to provide a static template in the form of a string value (which may be originating from a file in which case you only provide the file name) which may contain static text, and actions which are processed and executed when the engine processes the template and generates the output.

You may provide parameters which are included/substituted in the static template and which may control the output generation process. Typical form of such parameters are structs and map values which may be nested.

Example:

For example let's say you want to generate email messages that look like this:

Hi [name]!

Your account is ready, your user name is: [user-name]

You have the following roles assigned:
[role#1], [role#2], ... [role#n]

To generate email message bodies like this, you could use the following static template:

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

And provide data like this for executing it:

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

Normally output of templates are written to an io.Writer, so if you want the result as a string, create and write to a bytes.Buffer (which implements io.Writer). Executing the template and getting the result as 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()

This will result in the expected output:

Hi Bob!

Your account is ready, your user name is: bob92

You have the following roles assigned:
dbteam, uiteam, tester

Try it on the Go Playground.

Also note that since Go 1.10, a newer, faster, more specialized alternative is available to bytes.Buffer which is: strings.Builder. Usage is very similar:

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

Try this one on the Go Playground.

Note: you may also display the result of a template execution if you provide os.Stdout as the target (which also implements io.Writer):

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

This will write the result directly to os.Stdout. Try this on the Go Playground.

答案3

得分: 7

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

package main

import "fmt"

func main() {
	
	address := "NYC"

	fmt.Sprintf("我住在 %v", address)

}

当你运行这段代码时,它不会输出任何内容。但是一旦你将Sprintf()赋值给一个单独的变量,它就可以用于将来的用途。

package main

import "fmt"

func main() {
	
	address := "NYC"

	fmt.Sprintf("我住在 %v", address)

	var city = fmt.Sprintf("住在 %v", address)
	fmt.Println("Michael", city)

}
英文:

try using Sprintf(); it will not print the output but save it for future purpose.
check this out.

package main

import "fmt"

func main() {
	
	address := "NYC"

	fmt.Sprintf("I live in %v", address)

}

when you run this code, it will not output anything. But once you assigned the Sprintf() to a separate variable, it can be used for future purposes.

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

得分: 4

fmt.Sprintf函数返回一个字符串,你可以以与fmt.Printf相同的方式格式化字符串。

英文:

fmt.Sprintf function returns a string and you can format the string the very same way you would have with fmt.Printf

答案5

得分: 3

我为字符串格式化创建了一个Go项目(它允许以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)
}

英文:

I've created go project for string formatting from template (it allow to format strings in C# or Python style) and by performance tests it is fater than fmt.Sprintf, you could find it here https://github.com/Wissance/stringFormatter

it works in following manner:


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

答案6

得分: 2

在你的情况下,你需要使用Sprintf()来格式化字符串。

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

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

s := fmt.Sprintf("早上好,我是%s,我在这里已经住了%d年了", "约翰", 20)

你的输出将是:

早上好,我是约翰,我在这里已经住了20年了。

英文:

In your case, you need to use Sprintf() for format string.

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

Sprintf formats according to a format specifier and returns the resulting string.

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

Your output will be :

> Good Morning, This is John and I'm living here from last 20 years.

答案7

得分: 0

我来到这个页面是为了寻找一种格式化错误字符串的方法。所以如果有人需要相同的帮助,你可以使用fmt.Errorf()函数。

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

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

英文:

I came to this page specifically looking for a way to format an error string. So if someone needs help with the same, you want to use the fmt.Errorf() function.

The method signature is func Errorf(format string, a ...interface{}) error.
It returns the formatted string as a value that satisfies the error interface.

You can look up more details in the documentation - https://golang.org/pkg/fmt/#Errorf.

答案8

得分: -2

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

英文:

Instead of using template.New, you can just use the new builtin with
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))
}

huangapple
  • 本文由 发表于 2012年6月21日 00:21:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/11123865.html
匿名

发表评论

匿名网友

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

确定