web-dev-qa-db-ja.com

印刷せずにGo文字列をフォーマットしますか?

文字列を印刷せずにGoで文字列をフォーマットする簡単な方法はありますか?

できます:

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

しかし、私はそれをさらに操作することができるように印刷されるのではなくフォーマットされた文字列が返されることを望みます。

私はまたのような何かをすることができます:

s := "foo: " + bar

しかし、フォーマット文字列が複雑な場合は読みにくくなり、1つまたは複数の部分が文字列ではなく、最初に変換する必要がある場合は面倒です。

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

もっと簡単な方法はありますか?

313
Carnegie

Sprintf はあなたが探しているものです。

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

また、 "A Tour of Go"の一部として、 エラーの例 でも使用されています。

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

単純な文字列

"単純な"文字列(通常は一行に収まるもの)の場合、最も簡単な解決策は 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]"

stringsのみを連結する場合は、 strings.Join() を使用することもできます。ここでは、(結合する文字列の間に配置される)カスタム区切り文字stringを指定できます。

これらを Go Playground で試してください。

複雑な文字列(ドキュメント)

作成しようとしている文字列がもっと複​​雑な場合(複数行の電子メールメッセージなど)、fmt.Sprintf()は読みにくく効率が悪くなります(特にこれを何度も行わなければならない場合)。

このため、標準ライブラリは text/templatehtml/template のパッケージを提供しています。これらのパッケージは、テキスト出力を生成するためのデータ駆動型テンプレートを実装しています。 html/templateはコードインジェクションに対して安全なHTML出力を生成するためのものです。これはパッケージtext/templateと同じインターフェースを提供し、出力がHTMLの場合はいつでもtext/templateの代わりに使用されるべきです。

templateパッケージを使用するには、基本的に静的テキストを含むことができるstring値(ファイル名のみを指定することができます)の形式で静的テンプレートを提供する必要があります。処理および実行されるアクションエンジンがテンプレートを処理して出力を生成したとき。

静的テンプレートに含まれている/置き換えられているパラメータ、および出力生成プロセスを制御できるパラメータを指定できます。そのようなパラメータの典型的な形式は、ネストすることができるstructsと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.Bufferio.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 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 Playground で試してみてください。

170
icza

あなたの場合、あなたはフォーマット文字列のために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年間、ここに住んでいます。

1
Kabeer Shaikh

fmt.SprintF関数は文字列を返すので、fmtと同じ方法で文字列をフォーマットできます。 PrintF

0
Mo-Gang