Go dizesi yazdırılmadan biçimlendirilsin mi?


381

Go'da bir dizeyi yazdırmadan dizeyi biçimlendirmenin basit bir yolu var mı?

Yapabilirim:

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

Ama biçimlendirilmiş dize yazdırmak yerine döndürmek istiyorum, böylece daha fazla manipüle edebilirsiniz.

Ayrıca şöyle bir şey yapabilirim:

s := "foo: " + bar

Ancak, biçim dizesi karmaşık olduğunda bunu okumak zorlaşır ve parçalardan biri veya daha fazlası dizeli olmadığında ve önce dönüştürülmesi gerektiğinde hantal

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

Bunu yapmanın daha basit bir yolu var mı?

Yanıtlar:


465

Sprintf aradığınız şey.

Misal

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

Kullanımda olanları "A Tour of Go" nun bir parçası olarak Hatalar örneğinde de görebilirsiniz .

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

6
% sonrası mektup önemli mi? % Y ve% q olabilir mi? veya% y ve% y
Filip Bartuzi

17
Harf önemli, buna fiil denir, temel olarak Sprintf'e değişkenin ne tür olduğunu bilmesini sağlar, böylece 65 alırsa ve fiil% d ise 65 sayısını basar, ancak fiil% c ise karakteri basar 'A'. Bkz: golang.org/pkg/fmt/#hdr-Baskı
redsalt

2
Neden Sprintf deniyor? String için S, format için f? İşlev ekrana çıkmazsa, baskının işlev adının bir parçası olması tuhaftır. Bu beni bir süre
şaşırttı

194

1. Basit dizeler

"Basit" dizeler için (genellikle bir çizgiye uyan) en basit çözüm fmt.Sprintf()ve arkadaşlar ( fmt.Sprint(), fmt.Sprintln()) kullanmaktır. Bunlar başlangıç Sharfi olmayan işlevlere benzer , ancak bu Sxxx()varyantlar sonucu stringstandart çıktıya yazdırmak yerine sonucu döndürür .

Örneğin:

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

Değişken sşu değerle başlatılır:

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

İpucu: Yalnızca farklı türdeki değerleri birleştirmek istiyorsanız, tam olarak bunu yaptığınız gibi otomatik olarak Sprintf()(biçim dizesi gerektiren) kullanmanız gerekmeyebilir Sprint(). Bu örneğe bakın:

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

Yalnızca s'leri birleştirmek için string, strings.Join()özel bir ayırıcı string(birleştirilecek dizeler arasına yerleştirilecek) belirtebileceğiniz yeri de kullanabilirsiniz .

Bunları Go Playground'da deneyin .

2. Karmaşık dizeler (belgeler)

Oluşturmaya çalıştığınız dize daha karmaşıksa (örneğin çok satırlı bir e-posta iletisi), fmt.Sprintf()daha az okunabilir ve daha az verimli olur (özellikle bunu birçok kez yapmanız gerekiyorsa).

Bunun için standart kütüphane paketleri text/templateve sağlar html/template. Bu paketler, metin çıktısı oluşturmak için veriye dayalı şablonlar uygular. html/templatekod enjeksiyonuna karşı güvenli HTML çıktısı oluşturmak içindir. Paketle aynı arabirimi sağlar ve çıktı HTML olduğunda text/templatedeğil kullanılmalıdır text/template.

templatePaketleri kullanmak, temel olarak, stringstatik metin içerebilecek bir değer (bir dosyadan kaynaklanıyor olabilir, bu durumda yalnızca dosya adını verebilirsiniz) şeklinde statik bir şablon ve motoru şablonu işler ve çıktıyı üretir.

Statik şablona dahil edilen / değiştirilen ve çıktı oluşturma işlemini kontrol edebilen parametreler sağlayabilirsiniz. Bu tür parametrelerin tipik formu, iç içe olabilecek structs ve mapdeğerlerdir.

Misal:

Örneğin, şöyle görünen bir e-posta mesajı oluşturmak istediğinizi varsayalım:

Hi [name]!

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

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

Bunun gibi e-posta mesajı gövdeleri oluşturmak için aşağıdaki statik şablonu kullanabilirsiniz:

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

Ve yürütmek için böyle veriler sağlayın:

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

Normalde şablonların çıktıları bir 'e yazılır io.Writer, bu nedenle sonucu bir olarak istiyorsanız, stringbir bytes.Buffer(uygular io.Writer) oluşturun ve üzerine yazın . Şablonu yürütme ve sonucu şu şekilde alma 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()

Bu beklenen çıktı ile sonuçlanacaktır:

Hi Bob!

Your account is ready, your user name is: bob92

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

Go Playground'da deneyin .

Ayrıca Go 1.10, çünkü daha yeni, daha hızlı, daha uzmanlaşmış bir alternatif mevcut olduğuna dikkat bytes.Bufferhangi: strings.Builder. Kullanımı çok benzer:

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

Bunu Go Playground'da deneyin .

Not: os.StdoutHedef olarak sağlarsanız (ayrıca uygular io.Writer) şablon yürütme sonucunu da görüntüleyebilirsiniz :

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

Bu, sonucu doğrudan adresine yazacaktır os.Stdout. Bunu Go Playground'da deneyin .


2

Sizin durumunuzda, format dizesi için Sprintf () kullanmanız gerekir.

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

Sprintf, bir format belirleyicisine göre formatlar ve elde edilen dizeyi döndürür.

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

Çıktınız:

Günaydın, bu John ve ben son 20 yıldan beri burada yaşıyorum.


0

fmt.SprintF işlevi bir dize döndürür ve dizeyi fmt.PrintF ile aynı şekilde biçimlendirebilirsiniz.


0

Özel bir Dize türünü destek define new Typeile özelleştirebiliriz Format.

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)
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.