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

bkhjykvo  于 2023-05-11  发布在  Go
关注(0)|答案(8)|浏览(243)

有没有一种简单的方法可以在Go中格式化一个字符串而不打印字符串?
我可以做到:

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

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

s := "foo: " + bar

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

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

有没有更简单的方法?

hfsqlsce

hfsqlsce1#

Sprintf就是你要找的。

示例

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

您还可以在Errors example中看到它作为“A Tour of Go”的一部分使用。

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

ars1skjm2#

1.简单字符串

对于“简单”字符串(通常适合一行),最简单的解决方案是使用fmt.Sprintf()和friends(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 s,您也可以使用strings.Join(),其中可以指定自定义分隔符string(将放置在要连接的字符串之间)。
Go Playground上试试这些。

2.复杂字符串(文档)

如果你要创建的字符串比较复杂(例如多行电子邮件),fmt.Sprintf()的可读性和效率会降低(特别是当您必须多次执行此操作时)。
为此,标准库提供了text/templatehtml/template包。这些包实现了用于生成文本输出的数据驱动模板。html/template用于生成安全的HTML输出,以防止代码注入。它提供了与text/template包相同的接口,只要输出是HTML,就应该使用它来代替text/template
使用template软件包基本上需要您提供一个string值形式的静态模板(它可能来自一个文件,在这种情况下,您只需提供文件名),其中可能包含静态文本,以及当引擎处理模板并生成输出时处理和执行的操作。
您可以提供包含/替换在静态模板中的参数,这些参数可以控制输出生成过程。这种参数的典型形式是可以嵌套的struct s和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上试试这个。

mu0hgdu0

mu0hgdu03#

尝试使用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)

}
8qgya5xd

8qgya5xd4#

我已经创建了一个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)
}
r7knjye2

r7knjye25#

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

snvhrwxg

snvhrwxg6#

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

kqhtkvqz

kqhtkvqz7#

我来到这个页面是为了寻找一种格式化错误字符串的方法。因此,如果有人需要同样的帮助,您可以使用fmt.Errorf()函数。
方法签名是func Errorf(format string, a ...interface{}) error。它将格式化的字符串作为满足error接口的值返回。
您可以在文档中查找更多详细信息-https://golang.org/pkg/fmt/#Errorf。

uxh89sit

uxh89sit8#

你可以直接使用new内建的模板,而不是使用template.New。模板:

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

相关问题