445 votes

Formater une chaîne de caractères Go sans imprimer ?

Existe-t-il un moyen simple de formater une chaîne de caractères en Go sans l'imprimer ?

Je peux le faire :

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

Mais je veux que la chaîne formatée soit renvoyée plutôt qu'imprimée afin de pouvoir la manipuler davantage.

Je pourrais aussi faire quelque chose comme :

s := "foo: " + bar

Mais cela devient difficile à lire lorsque la chaîne de format est complexe, et fastidieux lorsqu'une ou plusieurs des parties ne sont pas des chaînes et doivent être converties en premier, comme par exemple

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

Existe-t-il un moyen plus simple de procéder ?

543voto

Sonia Points 6077

Sprintf est ce que vous recherchez.

Exemple

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

Vous pouvez également le voir en action dans le Exemple d'erreurs dans le cadre de "A Tour of Go".

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

7 votes

La lettre après le % a-t-elle de l'importance ? Serait-ce %y et %q ? ou %y et %y ?

22 votes

La lettre a de l'importance, c'est ce qu'on appelle un verbe, qui permet à Sprintf de savoir de quel type est la variable. Ainsi, si elle reçoit 65 et que le verbe est %d, elle imprimera le nombre 65, mais si le verbe est %c, elle imprimera le caractère 'A'. Voir : golang.org/pkg/fmt/#hdr-Printing

4 votes

Pourquoi s'appelle-t-il Sprintf ? S pour string, f pour format ? Il est étrange que print fasse partie du nom de la fonction si la fonction ne sort pas à l'écran. Cela m'a laissé perplexe pendant un certain temps...

237voto

icza Points 3857

1. Cordes simples

Pour les chaînes "simples" (typiquement ce qui tient dans une ligne), la solution la plus simple est d'utiliser fmt.Sprintf() et ses amis ( fmt.Sprint() , fmt.Sprintln() ). Celles-ci sont analogues aux fonctions sans le démarreur S lettre, mais ces Sxxx() variants renvoient le résultat sous la forme d'un string au lieu de les imprimer sur la sortie standard.

Par exemple :

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

La variable s sera initialisé avec cette valeur :

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

Conseil : Si vous souhaitez simplement concaténer des valeurs de différents types, vous n'aurez peut-être pas automatiquement besoin d'utiliser la commande Sprintf() (qui nécessite une chaîne de format) comme Sprint() fait exactement cela. Voir cet exemple :

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

Pour la concaténation uniquement string vous pouvez également utiliser strings.Join() où vous pouvez spécifier un séparateur personnalisé string (à placer entre les cordes à joindre).

Essayez-les sur le Go Playground .

2. Chaînes complexes (documents)

Si la chaîne que vous essayez de créer est plus complexe (par exemple, un message électronique de plusieurs lignes), fmt.Sprintf() devient moins lisible et moins efficace (surtout si vous devez le faire plusieurs fois).

Pour cela, la bibliothèque standard fournit les paquets text/template y html/template . Ces paquets mettent en œuvre des modèles axés sur les données pour générer une sortie textuelle. html/template sert à générer une sortie HTML sécurisée contre l'injection de code. Il fournit la même interface que le paquet text/template et devrait être utilisé à la place de text/template lorsque la sortie est en HTML.

Utilisation de la template vous demande essentiellement de fournir un modèle statique sous la forme d'un fichier string la valeur (qui peut provenir d'un fichier, auquel cas vous ne fournissez que le nom du fichier) qui peut contenir du texte statique, et les actions qui sont traitées et exécutées lorsque le moteur traite le modèle et génère la sortie.

Vous pouvez fournir des paramètres qui sont inclus/substitués dans le modèle statique et qui peuvent contrôler le processus de génération de la sortie. Les formes typiques de tels paramètres sont struct et map qui peuvent être imbriquées.

Exemple :

Par exemple, disons que vous voulez générer des messages électroniques qui ressemblent à ceci :

Hi [name]!

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

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

Pour générer des corps de messages électroniques comme celui-ci, vous pouvez utiliser le modèle statique suivant :

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

Et fournir des données comme celles-ci pour l'exécuter :

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

Normalement, la sortie des modèles est écrite dans un fichier de type io.Writer donc si vous voulez que le résultat soit un string créer et écrire dans un bytes.Buffer (qui met en œuvre io.Writer ). En exécutant le modèle, on obtient le résultat suivant 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()

Vous obtiendrez ainsi le résultat escompté :

Hi Bob!

Your account is ready, your user name is: bob92

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

Essayez-le sur le Go Playground .

Notez également que depuis Go 1.10, une alternative plus récente, plus rapide et plus spécialisée est disponible pour bytes.Buffer qui est : strings.Builder . L'utilisation est très similaire :

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

Essayez celui-ci sur le Go Playground .

Remarque : vous pouvez également afficher le résultat de l'exécution d'un modèle si vous indiquez os.Stdout comme cible (qui implémente également io.Writer ):

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

Ceci écrira le résultat directement dans os.Stdout . Essayez ceci sur le Go Playground .

5voto

Randil Tennakoon Points 373

Essayez d'utiliser Sprintf() il n'imprimera pas la sortie mais l'enregistrera pour un usage ultérieur. Vérifiez ceci.

package main

import "fmt"

func main() {

    address := "NYC"

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

}

lorsque vous exécutez ce code, il ne produira rien. Mais une fois que vous avez assigné le Sprintf() à une variable distincte, elle pourra être utilisée à des fins ultérieures.

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)

}

3voto

Kabeer Shaikh Points 201

Dans votre cas, vous devez utiliser Sprintf() pour la chaîne de format.

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

Sprintf formate selon un spécificateur de format et renvoie la chaîne résultante.

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

Votre résultat sera :

Bonjour, je m'appelle John et je vis ici depuis 20 ans.

2voto

ahuigo Points 878

Nous pouvons personnaliser un nouveau type de String via define new Type avec Format soutien.

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

Note : {{.}} représenter {{$r}} sur {{range $i, $r := .Roles}} {{.}} {{end}}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X