Форматировать строку Go без печати?

Есть ли простой способ отформатировать строку в Go без печати строки?

Я могу сделать:

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

Но я хочу, чтобы отформатированная строка возвращалась, а не печаталась, чтобы я мог манипулировать ею дальше.

Я также мог бы сделать что-то вроде:

s := "foo: " + bar

Но это становится трудным для чтения, когда строка формата является сложной, и громоздкой, когда одна или несколько частей не являются строками и должны быть сначала преобразованы, как

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

Есть ли более простой способ сделать это?

Ответ 1

Sprintf - это то, что вы ищете.

пример

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

Вы также можете увидеть его в примере с ошибками как часть "Тур по Го".

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

Ответ 2

1. Простые строки

Для "простых" строк (обычно для строк) самое простое решение - использовать fmt.Sprintf() и friends ( 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.

Ответ 3

В вашем случае вам нужно использовать 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 лет.

Ответ 4

Функция fmt.SprintF возвращает строку, и вы можете отформатировать строку точно так же, как с fmt.PrintF