จัดรูปแบบสตริง Go โดยไม่พิมพ์หรือไม่


381

มีวิธีง่ายๆในการจัดรูปแบบสตริงใน Go โดยไม่ต้องพิมพ์สตริงหรือไม่?

ที่ฉันสามารถทำได้:

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

แต่ฉันต้องการสตริงที่ฟอร์แมทที่ส่งคืนแทนที่จะพิมพ์เพื่อให้ฉันสามารถจัดการกับมันต่อไป

ฉันสามารถทำสิ่งที่ชอบ:

s := "foo: " + bar

แต่สิ่งนี้กลายเป็นเรื่องยากที่จะอ่านเมื่อสตริงรูปแบบซับซ้อนและยุ่งยากเมื่อส่วนหนึ่งหรือหลายส่วนไม่ใช่สตริงและต้องถูกแปลงก่อนเช่น

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

มีวิธีที่ง่ายกว่านี้หรือไม่?

คำตอบ:


465

Sprintfคือสิ่งที่คุณกำลังมองหา

ตัวอย่าง

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

คุณสามารถดูได้ในตัวอย่างข้อผิดพลาดซึ่งเป็นส่วนหนึ่งของ "A Tour of Go"

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

6
ตัวอักษรหลังจาก% มีความสำคัญอย่างไร เป็น% y และ% q ได้ไหม หรือ% y และ% y
Filip Bartuzi

17
ตัวอักษรมีความสำคัญเรียกว่ากริยาโดยทั่วไปแล้วมันทำให้ Sprintf รู้ว่าตัวแปรคืออะไรถ้ารับ 65 และกริยาคือ% d มันจะพิมพ์ตัวเลข 65 แต่ถ้ากริยาคือ% c มันจะพิมพ์ตัวอักษร 'A' ดู: golang.org/pkg/fmt/#hdr-Printing
redsalt

2
ทำไมถึงเรียกว่า Sprintf S สำหรับสตริง, f สำหรับรูปแบบ? มันแปลกที่การพิมพ์เป็นส่วนหนึ่งของชื่อฟังก์ชั่นถ้าฟังก์ชั่นไม่ได้ส่งออกไปยังหน้าจอ เรื่องนี้ทำให้ฉันงุนงงอยู่พักนึง ...
jcollum

194

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]"

สำหรับการต่อข้อมูลstrings เท่านั้นคุณสามารถใช้strings.Join()ตำแหน่งที่คุณสามารถระบุตัวคั่นแบบกำหนดเองstring(เพื่อวางระหว่างสตริงเพื่อเข้าร่วม)

ลองเหล่านี้ในไปสนามเด็กเล่น

2. สตริงที่ซับซ้อน (เอกสาร)

หากสตริงที่คุณพยายามสร้างมีความซับซ้อนมากขึ้น (เช่นข้อความอีเมลหลายบรรทัด) fmt.Sprintf()จะสามารถอ่านได้และมีประสิทธิภาพน้อยลง (โดยเฉพาะถ้าคุณต้องทำหลายครั้ง)

สำหรับวันนี้ห้องสมุดมาตรฐานให้แพคเกจและtext/template html/templateแพคเกจเหล่านี้ใช้แม่แบบที่ขับเคลื่อนด้วยข้อมูลเพื่อสร้างเอาต์พุตแบบข้อความ html/templateใช้สำหรับสร้างเอาต์พุต HTML ที่ปลอดภัยต่อการฉีดรหัส มันมีอินเตอร์เฟสเหมือนกับแพ็คเกจtext/templateและควรใช้แทนtext/templateเมื่อใดก็ตามที่เอาต์พุตเป็น HTML

การใช้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 $i}}, {{end}}{{.}}{{end}}
`

และให้ข้อมูลเช่นนี้เพื่อดำเนินการ:

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

โดยปกติแล้วเอาต์พุตของเทมเพลตจะถูกเขียนไปที่ a io.Writerดังนั้นหากคุณต้องการผลลัพธ์ที่เป็น a stringให้สร้างและเขียนไปที่ a 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

ลองใช้ในสนามเด็กเล่นไป

นอกจากนี้ยังทราบว่าตั้งแต่ไป 1.10, ใหม่, ทางเลือกที่เร็วขึ้น, ความเชี่ยวชาญมากขึ้นสามารถใช้ได้กับซึ่งเป็น:bytes.Buffer strings.Builderการใช้งานคล้ายกันมาก:

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

ลองหนึ่งในนี้ไปสนามเด็กเล่น

หมายเหตุ: คุณอาจแสดงผลลัพธ์ของการเรียกใช้เทมเพลตหากคุณระบุ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นี้จะเขียนผลโดยตรงกับ ลองนี้บนไปสนามเด็กเล่น


2

ในกรณีของคุณคุณต้องใช้ 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 ปีแล้ว


0

ฟังก์ชันfmt.SprintFส่งคืนสตริงและคุณสามารถจัดรูปแบบสตริงในลักษณะเดียวกับที่คุณใช้กับfmt.PrintF


0

เราสามารถกำหนดประเภทสตริงใหม่ได้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)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.