¿Formatear una cadena Go sin imprimir?
¿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?
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)
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 S
letra inicial, pero estas Sxxx()
variantes devuelven el resultado como en string
lugar 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 s
se 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 string
electró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/template
y html/template
. Estos paquetes implementan plantillas basadas en datos para generar resultados textuales. html/template
es para generar resultados HTML seguros contra la inyección de código. Proporciona la misma interfaz que el paquete text/template
y debe usarse en lugar de text/template
cuando la salida sea HTML.
El uso de los template
paquetes básicamente requiere que usted proporcione una plantilla estática en forma de string
valor (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 struct
s y map
valores 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.Buffer
que 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.Stdout
como 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 .
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)
}