Formattare una stringa Go senza stampare?


381

Esiste un modo semplice per formattare una stringa in Go senza stamparla?

Posso fare:

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

Voglio che la stringa formattata venga restituita anziché stampata in modo da poterla manipolare ulteriormente.

Potrei anche fare qualcosa del tipo:

s := "foo: " + bar

Ma questo diventa difficile da leggere quando la stringa di formato è complessa e ingombrante quando una o più parti non sono stringhe e devono essere convertite per prime, come

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

C'è un modo più semplice per farlo?

Risposte:


465

Sprintf è quello che stai cercando.

Esempio

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

Puoi anche vederlo in uso nell'esempio Errori come parte di "A Tour of Go".

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

6
importa la lettera dopo%? Potrebbe essere% ye% q? o% ye% y
Filip Bartuzi,

17
La lettera è importante, si chiama verbo, in sostanza fa sapere a Sprintf che tipo è la variabile in modo che se riceve 65 e il verbo è% d stamperà il numero 65 ma se il verbo è% c stamperà il carattere 'UN'. Vedi: golang.org/pkg/fmt/#hdr-Printing
redsalt

2
Perché si chiama Sprintf? S per stringa, f per formato? È strano che la stampa faccia parte del nome della funzione se la funzione non viene visualizzata sullo schermo. Questo mi ha
lasciato

194

1. Stringhe semplici

Per stringhe "semplici" (in genere ciò che si inserisce in una linea) sta usando la soluzione più semplice fmt.Sprintf()e friends ( fmt.Sprint(), fmt.Sprintln()). Queste sono analoghe alle funzioni senza la Slettera iniziale , ma queste Sxxx()varianti restituiscono il risultato stringanziché stamparle sull'output standard.

Per esempio:

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

La variabile sverrà inizializzata con il valore:

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

Suggerimento: se si desidera semplicemente concatenare valori di tipi diversi, potrebbe non essere necessario utilizzare automaticamente Sprintf()(che richiede una stringa di formato) Sprint()esattamente come questo. Vedi questo esempio:

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

Per concatenare solo stringi messaggi di posta elettronica , è anche possibile utilizzare strings.Join()dove è possibile specificare un separatore personalizzato string(da posizionare tra le stringhe da unire).

Prova questi sul Go Playground .

2. Stringhe complesse (documenti)

Se la stringa che stai cercando di creare è più complessa (ad esempio un messaggio di posta elettronica su più righe), fmt.Sprintf()diventa meno leggibile e meno efficiente (soprattutto se devi farlo molte volte).

Per questo la libreria standard fornisce i pacchetti text/templatee html/template. Questi pacchetti implementano modelli basati sui dati per generare output testuali. html/templateè per generare output HTML sicuro contro l'iniezione di codice. Fornisce la stessa interfaccia del pacchetto text/templatee dovrebbe essere usato invece text/templateogni volta che l'output è HTML.

L'uso dei templatepacchetti richiede fondamentalmente di fornire un modello statico sotto forma di un stringvalore (che potrebbe provenire da un file nel qual caso si fornisce solo il nome del file) che può contenere testo statico e azioni che vengono elaborate ed eseguite quando il engine elabora il modello e genera l'output.

È possibile fornire parametri che sono inclusi / sostituiti nel modello statico e che possono controllare il processo di generazione dell'output. Forma tipica di tali parametri sono structs e mapvalori che possono essere annidate.

Esempio:

Ad esempio, supponiamo che tu voglia generare messaggi di posta elettronica simili a questo:

Hi [name]!

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

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

Per generare corpi di messaggi di posta elettronica come questo, è possibile utilizzare il seguente modello statico:

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

E fornisci dati come questo per eseguirlo:

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

Normalmente l'output dei modelli viene scritto in un io.Writer, quindi se si desidera il risultato come un string, creare e scrivere in un bytes.Buffer(che implementa io.Writer). Eseguire il modello e ottenere il risultato come 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()

Ciò comporterà l'output previsto:

Hi Bob!

Your account is ready, your user name is: bob92

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

Provalo sul Go Playground .

Si noti inoltre che dal Go 1.10, un nuovo, un'alternativa più veloce, più specializzato è a disposizione per bytes.Bufferla quale è: strings.Builder. L'utilizzo è molto simile:

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

Prova questo sul Go Playground .

Nota: è anche possibile visualizzare il risultato di un'esecuzione del modello se si fornisce os.Stdoutcome destinazione (che implementa anche io.Writer):

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

Questo scriverà il risultato direttamente su os.Stdout. Prova questo sul Go Playground .


2

Nel tuo caso, devi usare Sprintf () per la stringa di formato.

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

Sprintf formati secondo un identificatore di formato e restituisce la stringa risultante.

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

Il tuo output sarà:

Buongiorno, sono John e vivo qui da 20 anni.


0

La funzione fmt.SprintF restituisce una stringa e puoi formattare la stringa nello stesso modo che avresti con fmt.PrintF


0

Possiamo abitudine Un nuovo tipo String via define new Typecon Formatil supporto.

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)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.