¿Formatear una cadena Go sin imprimir?

Resuelto Carnegie asked hace 12 años • 8 respuestas

¿Existe una forma sencilla de formatear una cadena en Go sin imprimir la cadena?

Puedo hacer:

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

Pero quiero que se devuelva la cadena formateada en lugar de imprimirla para poder manipularla más.

También podría hacer algo como:

s := "foo: " + bar

Pero esto se vuelve difícil de leer cuando la cadena de formato es compleja, y engorroso cuando una o muchas de las partes no son cadenas y deben convertirse primero, como

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

¿Existe una forma más sencilla de hacer esto?

Carnegie avatar Jun 20 '12 23:06 Carnegie
Aceptado

Sprintf es lo que estás buscando.

Ejemplo

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

También puedes verlo en uso en el ejemplo de Errores como parte de "Un recorrido por Go".

return fmt.Sprintf("at %v, %s", e.When, e.What)
Sonia avatar Jun 20 '2012 16:06 Sonia

1. Cuerdas simples

Para cadenas "simples" (normalmente las que caben en una línea), la solución más sencilla es utilizar fmt.Sprintf()and friends ( fmt.Sprint(), fmt.Sprintln()). Son análogas a las funciones sin la Sletra inicial, pero estas Sxxx()variantes devuelven el resultado como en stringlugar de imprimirlos en la salida estándar.

Por ejemplo:

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

La variable sse inicializará con el valor:

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

Consejo: Si solo desea concatenar valores de diferentes tipos, es posible que no necesite usar automáticamente Sprintf()(lo que requiere una cadena de formato) como Sprint()hace exactamente esto. Vea este ejemplo:

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

Para concatenar solo correos stringelectrónicos, también puede usar strings.Join()donde puede especificar un separador personalizado string(que se colocará entre las cadenas a unir).

Pruébelos en Go Playground .

2. Cadenas complejas (documentos)

Si la cadena que intenta crear es más compleja (por ejemplo, un mensaje de correo electrónico de varias líneas), fmt.Sprintf()se vuelve menos legible y menos eficiente (especialmente si tiene que hacer esto muchas veces).

Para ello, la biblioteca estándar proporciona los paquetes text/templatey html/template. Estos paquetes implementan plantillas basadas en datos para generar resultados textuales. html/templatees para generar resultados HTML seguros contra la inyección de código. Proporciona la misma interfaz que el paquete text/templatey debe usarse en lugar de text/templatecuando la salida sea HTML.

El uso de los templatepaquetes básicamente requiere que usted proporcione una plantilla estática en forma de stringvalor (que puede originarse en un archivo, en cuyo caso solo proporciona el nombre del archivo) que puede contener texto estático y acciones que se procesan y ejecutan cuando el El motor procesa la plantilla y genera la salida.

Puede proporcionar parámetros que se incluyen/sustituyen en la plantilla estática y que pueden controlar el proceso de generación de resultados. La forma típica de tales parámetros son structs y mapvalores que pueden estar anidados.

Ejemplo:

Por ejemplo, digamos que desea generar mensajes de correo electrónico con este aspecto:

Hi [name]!

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

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

Para generar cuerpos de mensajes de correo electrónico como este, puede utilizar la siguiente plantilla estática:

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

Y proporcione datos como este para ejecutarlo:

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

Normalmente, la salida de las plantillas se escribe en un io.Writer, por lo que si desea el resultado como string, cree y escriba en un bytes.Buffer(que implementa io.Writer). Ejecutando la plantilla y obteniendo el resultado como 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()

Esto dará como resultado el resultado esperado:

Hi Bob!

Your account is ready, your user name is: bob92

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

Pruébelo en Go Playground .

También tenga en cuenta que desde Go 1.10, hay disponible una alternativa más nueva, más rápida y más especializada, bytes.Bufferque es: strings.Builder. El uso es muy similar:

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

Pruebe este en Go Playground .

Nota: también puede mostrar el resultado de la ejecución de una plantilla si proporciona os.Stdoutcomo destino (que también implementa io.Writer):

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

Esto escribirá el resultado directamente en os.Stdout. Pruebe esto en Go Playground .

icza avatar Jul 31 '2015 09:07 icza

intenta usar Sprintf(); no imprimirá el resultado, pero lo guardará para fines futuros. mira esto.

package main

import "fmt"

func main() {
    
    address := "NYC"

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

}

cuando ejecuta este código, no generará nada. Pero una vez que haya asignado el Sprintf()a una variable separada, podrá usarlo para propósitos futuros.

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)

}
Kalhara Tennakoon avatar May 31 '2021 03:05 Kalhara Tennakoon