Форматировать строку Go без печати?
Есть ли простой способ отформатировать строку в Go без печати строки?
Я могу сделать:
bar := "bar"
fmt.Printf("foo: %s", bar)
Но я хочу, чтобы отформатированная строка возвращалась, а не печаталась, чтобы я мог манипулировать ею дальше.
Я также мог бы сделать что-то вроде:
s := "foo: " + bar
Но это становится трудным для чтения, когда строка формата является сложной, и громоздкой, когда одна или несколько частей не являются строками и должны быть сначала преобразованы, как
i := 25
s := "foo: " + strconv.Itoa(i)
Я очень новичок в Go - мой опыт работы в Ruby, где это просто. Есть ли более простой способ сделать это?
9 ответов
Вот также использование этого в учебнике, "Тур по Го".
return fmt.Sprintf("at %v, %s", e.When, e.What)
1. Простые строки
Для "простых" строк (как правило, то, что вписывается в строку) самое простое решение использует fmt.Sprintf()
и друзья (fmt.Sprint()
, fmt.Sprintln()
). Они аналогичны функциям без стартера S
письмо, но эти Sxxx()
варианты возвращают результат в виде string
вместо печати их на стандартный вывод.
Например:
s := fmt.Sprintf("Hi, my name is %s and I'm %d years old.", "Bob", 23)
Переменная s
будет инициализирован значением:
Hi, my name is Bob and I'm 23 years old.
Совет: если вы просто хотите объединить значения разных типов, вам может не потребоваться автоматически использовать Sprintf()
(который требует строку формата) как Sprint()
делает именно это Смотрите этот пример:
i := 23
s := fmt.Sprint("[age:", i, "]") // s will be "[age:23]"
Только для объединения string
s, вы также можете использовать strings.Join()
где вы можете указать пользовательский разделитель string
(быть помещенным между строками, чтобы присоединиться).
Попробуйте это на игровой площадке Go.
2. Сложные строки (документы)
Если строка, которую вы пытаетесь создать, является более сложной (например, многострочное сообщение электронной почты), fmt.Sprintf()
становится менее читабельным и менее эффективным (особенно если вам приходится делать это много раз).
Для этого стандартная библиотека предоставляет пакеты text/template
а также html/template
, Эти пакеты реализуют управляемые данными шаблоны для генерации текстового вывода. html/template
предназначен для генерации HTML-вывода, защищенного от внедрения кода. Предоставляет тот же интерфейс, что и пакет text/template
и должен использоваться вместо text/template
всякий раз, когда вывод HTML.
С использованием template
Пакеты в основном требуют, чтобы вы предоставили статический шаблон в виде string
значение (которое может происходить из файла, в этом случае вы указываете только имя файла), которое может содержать статический текст, а также действия, которые обрабатываются и выполняются, когда механизм обрабатывает шаблон и генерирует выходные данные.
Вы можете предоставить параметры, которые включены / заменены в статическом шаблоне и которые могут управлять процессом генерации вывода. Типичная форма таких параметров struct
с и map
значения, которые могут быть вложенными.
Пример:
Например, допустим, вы хотите генерировать сообщения электронной почты, которые выглядят так:
Hi [name]!
Your account is ready, your user name is: [user-name]
You have the following roles assigned:
[role#1], [role#2], ... [role#n]
Для создания таких сообщений электронной почты вы можете использовать следующий статический шаблон:
const emailTmpl = `Hi {{.Name}}!
Your account is ready, your user name is: {{.UserName}}
You have the following roles assigned:
{{range $i, $r := .Roles}}{{if ne $i 0}}, {{end}}{{.}}{{end}}
`
И предоставьте такие данные для его выполнения:
data := map[string]interface{}{
"Name": "Bob",
"UserName": "bob92",
"Roles": []string{"dbteam", "uiteam", "tester"},
}
Обычно выходные шаблоны записываются в io.Writer
так что если вы хотите, чтобы результат как string
создать и написать bytes.Buffer
(который реализует io.Writer
). Выполнение шаблона и получение результата в виде 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()
Это приведет к ожидаемому результату:
Hi Bob!
Your account is ready, your user name is: bob92
You have the following roles assigned:
dbteam, uiteam, tester
Попробуйте это на игровой площадке Go.
Также обратите внимание, что начиная с Go 1.10, доступна более новая, более быстрая и специализированная альтернатива bytes.Buffer
который: strings.Builder
, Использование очень похоже:
builder := &strings.Builder{}
if err := t.Execute(builder, data); err != nil {
panic(err)
}
s := builder.String()
Попробуйте это на Go Playground.
Примечание: вы также можете отобразить результат выполнения шаблона, если вы предоставите os.Stdout
в качестве цели (которая также реализует io.Writer
):
t := template.Must(template.New("email").Parse(emailTmpl))
if err := t.Execute(os.Stdout, data); err != nil {
panic(err)
}
Это запишет результат напрямую os.Stdout
, Попробуйте это на игровой площадке Go.
попробуйте использовать; он не распечатает результат, а сохранит его для использования в будущем. Проверь это.
package main
import "fmt"
func main() {
address := "NYC"
fmt.Sprintf("I live in %v", address)
}
когда вы запустите этот код, он ничего не выведет. Но как только вы назначили
Sprintf()
в отдельную переменную, его можно использовать в будущем.
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)
}
Функцияfmt.SprintF возвращает строку, и вы можете отформатировать строку точно так же, как и в fmt.PrintF.
В вашем случае вам нужно использовать Sprintf() для форматирования строки.
func Sprintf(format string, a ...interface{}) string
Sprintf форматирует в соответствии со спецификатором формата и возвращает полученную строку.
s := fmt.Sprintf("Good Morning, This is %s and I'm living here from last %d years ", "John", 20)
Ваш вывод будет:
Доброе утро, это Джон, и я живу здесь с прошлых 20 лет.
Я создал проект go для форматирования строк из шаблона (он позволяет форматировать строки в стиле C# или Python, только первая версия для очень простых случаев), вы можете найти его здесь https://github.com/Wissance/stringFormatter
он работает следующим образом:
func TestStrFormat(t *testing.T) {
strFormatResult, err := Format("Hello i am {0}, my age is {1} and i am waiting for {2}, because i am {0}!",
"Michael Ushakov (Evillord666)", "34", "\"Great Success\"")
assert.Nil(t, err)
assert.Equal(t, "Hello i am Michael Ushakov (Evillord666), my age is 34 and i am waiting for \"Great Success\", because i am Michael Ushakov (Evillord666)!", strFormatResult)
strFormatResult, err = Format("We are wondering if these values would be replaced : {5}, {4}, {0}", "one", "two", "three")
assert.Nil(t, err)
assert.Equal(t, "We are wondering if these values would be replaced : {5}, {4}, one", strFormatResult)
strFormatResult, err = Format("No args ... : {0}, {1}, {2}")
assert.Nil(t, err)
assert.Equal(t, "No args ... : {0}, {1}, {2}", strFormatResult)
}
func TestStrFormatComplex(t *testing.T) {
strFormatResult, err := FormatComplex("Hello {user} what are you doing here {app} ?", map[string]string{"user":"vpupkin", "app":"mn_console"})
assert.Nil(t, err)
assert.Equal(t, "Hello vpupkin what are you doing here mn_console ?", strFormatResult)
}
Мы можем настроить новый тип String через define new Type
с участием 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)
}
Я зашел на эту страницу специально в поисках способа отформатировать строку ошибки. Так что, если кому-то нужна помощь с тем же самым, вы можете использовать
fmt.Errorf()
функция.
Подпись метода
func Errorf(format string, a ...interface{}) error
. Он возвращает отформатированную строку как значение, удовлетворяющее
error
интерфейс.
Более подробную информацию можно найти в документации - https://golang.org/pkg/fmt/#Errorf.
Вместо использования
template.New
, вы можете просто использовать
new
встроенный с шаблоном .
package main
import (
"strings"
"text/template"
)
func format(s string, v interface{}) string {
t, b := new(template.Template), new(strings.Builder)
template.Must(t.Parse(s)).Execute(b, v)
return b.String()
}
func main() {
bar := "bar"
println(format("foo: {{.}}", bar))
i := 25
println(format("foo: {{.}}", i))
}