Implementing dynamic strings in golang - string

I have following global string,
studentName := "Hi ? ,Welcome"
Now I want to take this string dynamically
func returnName(name string) string{
return studentName+name
}
This function should return string as
Hi name,welcome.
string should take name from parameter,and return dynamic string.What is the best way to implement this in golang.

If you want to keep things simple, you can probably just use fmt.Sprintf.
studentName := fmt.Sprintf("Hi, %s! Welcome.", name)
The %s part will get replaced by the value of name.

If your input gets bigger (more complex) or if you need to substitute different values multiple times, then templates are more effective, cleaner and more flexible. Check out the text/template package.
The template package parses your template once, builts a tree from it, and once you need to replace values, it builds the output on the fly.
Take a look at this example:
const templ = `Hi {{.Name}}!
Welcome {{.Place}}.
Please bring {{.ToBring}}
`
You can parse such a template with this line:
t := template.Must(template.New("").Parse(templ))
Prepare its input data either as a struct or as a map:
data := map[string]string{
"Name": "Bob",
"Place": "Home",
"ToBring": "some beers",
}
And you can have the result with Template.Execute():
err := t.Execute(os.Stdout, data) // Prints result to the standard output
Here's the complete, runnable example: (try it on the Go Playground)
package main
import (
"os"
"text/template"
)
func main() {
data := map[string]string{
"Name": "Bob",
"Place": "Home",
"ToBring": "some beers",
}
t := template.Must(template.New("").Parse(templ))
if err := t.Execute(os.Stdout, data); err != nil { // Prints result to the standard output
panic(err)
}
// Now change something:
data["Name"] = "Alice"
data["ToBring"] = "a Teddy Bear"
if err := t.Execute(os.Stdout, data); err != nil {
panic(err)
}
}
const templ = `
Hi {{.Name}}!
Welcome {{.Place}}.
Please bring {{.ToBring}}
`
Output:
Hi Bob!
Welcome Home.
Please bring some beers
Hi Alice!
Welcome Home.
Please bring a Teddy Bear
Getting the result as a string:
If you want the result as a string, you can write the result to a bytes.Buffer and get the string using the Buffer.String() method:
buf := bytes.Buffer{}
t.Execute(&buf, data)
var result string = buf.String()
Complete program (try it on the Go Playground):
package main
import (
"bytes"
"fmt"
"text/template"
)
func main() {
data := map[string]string{
"Name": "Bob",
"Place": "Home",
"ToBring": "some beers",
}
fmt.Print(Execute(data))
}
var t = template.Must(template.New("").Parse(templ))
func Execute(data interface{}) string {
buf := bytes.Buffer{}
if err := t.Execute(&buf, data); err != nil {
fmt.Println("Error:", err)
}
return buf.String()
}
const templ = `
Hi {{.Name}}!
Welcome {{.Place}}.
Please bring {{.ToBring}}
`

You could consider the function strings.Replace
return Replace(studentName, "? ", name, 1)
With '1', it replaces the first "? " it finds in studentName.
Replace returns a copy of studentName, with "? " substituted with name.
This strictly respect the original question (global var with that exact content)
Now, if you start changing the question, like for instance with a different content (a global variable studentName := "Hi %s ,Welcome"), then you could use fmt.Sprintf() as in 425nesp's answer
return fmt.Sprintf(studentName, name)
That would use the format 'verbs' %s, default format for string.

Assuming the global string is always the same you could do.
func returnName(name string) string {
buf := bytes.Buffer{}
buf.WriteString("Hi ")
buf.WriteString(name)
buf.WriteString(", welcome")
return buf.String()
}
or
func returnName(name string) string {
return "Hi " + name + ", welcome"
}
if the string is a dynamic template you could use the template package or a simple Replace if there wont be other ? marks or Sprintf

You can also use template.Template
combined with strings.Builder:
package main
import (
"strings"
"text/template"
)
func returnName(name string) string {
t, b := new(template.Template), new(strings.Builder)
template.Must(t.Parse("Hi {{.}}, welcome.")).Execute(b, name)
return b.String()
}
func main() {
println(returnName("Akash"))
}

Related

Parse variable length array from csv to struct

I have the following setup to parse a csv file:
package main
import (
"fmt"
"os"
"encoding/csv"
)
type CsvLine struct {
Id string
Array1 [] string
Array2 [] string
}
func ReadCsv(filename string) ([][]string, error) {
f, err := os.Open(filename)
if err != nil {
return [][]string{}, err
}
defer f.Close()
lines, err := csv.NewReader(f).ReadAll()
if err != nil {
return [][]string{}, err
}
return lines, nil
}
func main() {
lines, err := ReadCsv("./data/sample-0.3.csv")
if err != nil {
panic(err)
}
for _, line := range lines {
fmt.Println(line)
data := CsvLine{
Id: line[0],
Array1: line[1],
Array2: line[2],
}
fmt.Println(data.Id)
fmt.Println(data.Array1)
fmt.Println(data.Array2)
}
}
And the following setup in my csv file:
594385903dss,"['fhjdsk', 'dfjdskl', 'fkdsjgooiertio']","['jflkdsjfl', 'fkjdlsfjdslkfjldks']"
87764385903dss,"['cxxc', 'wqeewr', 'opi', 'iy', 'qw']","['cvbvc', 'gf', 'mnb', 'ewr']"
My understanding is that variable length lists should be parsed into a slice, is it possible to do this directly via a csv reader? (The csv output was generated via a python project.)
Help/suggestions appreciated.
CSV does not have a notion of "variable length arrays", it is just a comma separated list of values. The format is described in RFC 4180, and that is exactly what the encoding/csv package implements.
You can only get a string slice out of a CSV line. How you interpret the values is up to you. You have to post process your data if you want to split it further.
What you have may be simply processed with the regexp package, e.g.
var r = regexp.MustCompile(`'[^']*'`)
func split(s string) []string {
parts := r.FindAllString(s, -1)
for i, part := range parts {
parts[i] = part[1 : len(part)-1]
}
return parts
}
Testing it:
s := `['one', 'two', 'three']`
fmt.Printf("%q\n", split(s))
s = `[]`
fmt.Printf("%q\n", split(s))
s = `['o,ne', 't,w,o', 't,,hree']`
fmt.Printf("%q\n", split(s))
Output (try it on the Go Playground):
["one" "two" "three"]
[]
["o,ne" "t,w,o" "t,,hree"]
Using this split() function, this is how processing may look like:
for _, line := range lines {
data := CsvLine{
Id: line[0],
Array1: split(line[1]),
Array2: split(line[2]),
}
fmt.Printf("%+v\n", data)
}
This outputs (try it on the Go Playground):
{Id:594385903dss Array1:[fhjdsk dfjdskl fkdsjgooiertio] Array2:[jflkdsjfl fkjdlsfjdslkfjldks]}
{Id:87764385903dss Array1:[cxxc wqeewr opi iy qw] Array2:[cvbvc gf mnb ewr]}

String splitting before character

I'm new to go and have been using split to my advantage. Recently I came across a problem I wanted to split something, and keep the splitting char in my second slice rather than removing it, or leaving it in the first slice as with SplitAfter.
For example the following code:
strings.Split("email#email.com", "#")
returned: ["email", "email.com"]
strings.SplitAfter("email#email.com", "#")
returned: ["email#", "email.com"]
What's the best way to get ["email", "#email.com"]?
Use strings.Index to find the # and slice to get the two parts:
var part1, part2 string
if i := strings.Index(s, "#"); i >= 0 {
part1, part2 = s[:i], s[i:]
} else {
// handle case with no #
}
Run it on the playground.
Could this work for you?
s := strings.Split("email#email.com", "#")
address, domain := s[0], "#"+s[1]
fmt.Println(address, domain)
// email #email.com
Then combing and creating a string
var buffer bytes.Buffer
buffer.WriteString(address)
buffer.WriteString(domain)
result := buffer.String()
fmt.Println(result)
// email#email.com
You can use bufio.Scanner:
package main
import (
"bufio"
"strings"
)
func email(data []byte, eof bool) (int, []byte, error) {
for i, b := range data {
if b == '#' {
if i > 0 {
return i, data[:i], nil
}
return len(data), data, nil
}
}
return 0, nil, nil
}
func main() {
s := bufio.NewScanner(strings.NewReader("email#email.com"))
s.Split(email)
for s.Scan() {
println(s.Text())
}
}
https://golang.org/pkg/bufio#Scanner.Split

Update a string value in loop

Is it possible to update the value of a string when we execute a for loop?
package main
import (
"fmt"
"strings"
)
func Chop(r int, s string) string {
return s[r:]
}
func main() {
s:= "ThisIsAstring1ThisIsAstring2ThisIsAstring3"
for strings.Contains(s, "string") {
// Original value > ThisIsAstring1ThisIsAstring2ThisIsAstring3
fmt.Println(s)
// I delete a part of the string > ThisIsAstring1
remove := len(s)/3
// Now, I update the value of string > string := ThisIsAstring2ThisIsAstring3
s := Chop(remove, s)
fmt.Println(s)
break
}
}
I don't know how to do it.
I have no clue what the use case is, but here goes. Let's start with identifying the issues in your code:
// You cannot use a reserved keyword "string" as a variable name
string:= "ThisIsAstring1ThisIsAstring2ThisIsAstring3"
for strings.Contains(string, "string") {
// Remove is a float, but you need to pass an int into your chop function
remove := len(string)/3
// You're reassigning your string variable. You really just want =, not :=
string := Chop(remove, string)
fmt.Println(string)
}
Now, here's a solution that will work for your use case:
str := "ThisIsAstring1ThisIsAstring2ThisIsAstring3"
for strings.Contains(str, "string") {
fmt.Println(str)
remove := int(len(str) / 3)
str = Chop(remove, str)
}
fmt.Println(str)
GoPlay:
https://play.golang.org/p/NdROIFDS_5

Go Templates: range over string

Is there any way to range over a string in Go templates (that is, from the code in the template itself, not from native Go)? It doesn't seem to be supported directly (The value of the pipeline must be an array, slice, map, or channel.), but is there some hack like splitting the string into an array of single-character strings or something?
Note that I am unable to edit any go source: I'm working with a compiled binary here. I need to make this happen from the template code alone.
You can use FuncMap to split string into characters.
package main
import (
"text/template"
"log"
"os"
)
func main() {
tmpl, err := template.New("foo").Funcs(template.FuncMap{
"to_runes": func(s string) []string {
r := []string{}
for _, c := range []rune(s) {
r = append(r, string(c))
}
return r
},
}).Parse(`{{range . | to_runes }}[{{.}}]{{end}}`)
if err != nil {
log.Fatal(err)
}
err = tmpl.Execute(os.Stdout, "hello world")
if err != nil {
log.Fatal(err)
}
}
This should be:
[h][e][l][l][o][ ][w][o][r][l][d]

How to print struct variables in console?

How can I print (to the console) the Id, Title, Name, etc. of this struct in Golang?
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data Data `json:"data"`
Commits Commits `json:"commits"`
}
To print the name of the fields in a struct:
fmt.Printf("%+v\n", yourProject)
From the fmt package:
when printing structs, the plus flag (%+v) adds field names
That supposes you have an instance of Project (in 'yourProject')
The article JSON and Go will give more details on how to retrieve the values from a JSON struct.
This Go by example page provides another technique:
type Response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
res2D := &Response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))
That would print:
{"page":1,"fruits":["apple","peach","pear"]}
If you don't have any instance, then you need to use reflection to display the name of the field of a given struct, as in this example.
type T struct {
A int
B string
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
fmt.Printf("%d: %s %s = %v\n", i,
typeOfT.Field(i).Name, f.Type(), f.Interface())
}
I want to recommend go-spew, which according to their github "Implements a deep pretty printer for Go data structures to aid in debugging"
go get -u github.com/davecgh/go-spew/spew
usage example:
package main
import (
"github.com/davecgh/go-spew/spew"
)
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data string `json:"data"`
Commits string `json:"commits"`
}
func main() {
o := Project{Name: "hello", Title: "world"}
spew.Dump(o)
}
output:
(main.Project) {
Id: (int64) 0,
Title: (string) (len=5) "world",
Name: (string) (len=5) "hello",
Data: (string) "",
Commits: (string) ""
}
my 2cents would be to use json.MarshalIndent -- surprised this isn't suggested, as it is the most straightforward. for example:
func prettyPrint(i interface{}) string {
s, _ := json.MarshalIndent(i, "", "\t")
return string(s)
}
no external deps and results in nicely formatted output.
I think it would be better to implement a custom stringer if you want some kind of formatted output of a struct
for example
package main
import "fmt"
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
}
func (p Project) String() string {
return fmt.Sprintf("{Id:%d, Title:%s, Name:%s}", p.Id, p.Title, p.Name)
}
func main() {
o := Project{Id: 4, Name: "hello", Title: "world"}
fmt.Printf("%+v\n", o)
}
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type
Alternatively, try using this function PrettyPrint()
// print the contents of the obj
func PrettyPrint(data interface{}) {
var p []byte
// var err := error
p, err := json.MarshalIndent(data, "", "\t")
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s \n", p)
}
In order to use this you do not need any additional packages with the exception of fmt and encoding/json, just a reference, pointer to, or literal of the struct you have created.
To use just take your struct, initialize it in main or whatever package you are in and pass it into PrettyPrint().
type Prefix struct {
Network string
Mask int
}
func valueStruct() {
// struct as a value
var nw Prefix
nw.Network = "10.1.1.0"
nw.Mask = 24
fmt.Println("### struct as a pointer ###")
PrettyPrint(&nw)
}
It's output would be
### struct as a pointer ###
{
"Network": "10.1.1.0",
"Mask": 24
}
Play around with the code here.
It is very convenient to use package fmt to output:
fmt.Printf("%+v \n", yourProject)
if you want to see the full type of the sturct, you can use # replace + :
fmt.Printf("%#v \n", yourProject)
I recommend to use Pretty Printer Library. In that you can print any struct very easily.
Install Library
https://github.com/kr/pretty
or
go get github.com/kr/pretty
Now do like this in your code
package main
import (
fmt
github.com/kr/pretty
)
func main(){
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data Data `json:"data"`
Commits Commits `json:"commits"`
}
fmt.Printf("%# v", pretty.Formatter(Project)) //It will print all struct details
fmt.Printf("%# v", pretty.Formatter(Project.Id)) //It will print component one by one.
}
Also you can get difference between component through this library and so more. You can also have a look on library Docs here.
I like litter.
From their readme:
type Person struct {
Name string
Age int
Parent *Person
}
litter.Dump(Person{
Name: "Bob",
Age: 20,
Parent: &Person{
Name: "Jane",
Age: 50,
},
})
Sdump is pretty handy in tests:
func TestSearch(t *testing.T) {
result := DoSearch()
actual := litterOpts.Sdump(result)
expected, err := ioutil.ReadFile("testdata.txt")
if err != nil {
// First run, write test data since it doesn't exist
if !os.IsNotExist(err) {
t.Error(err)
}
ioutil.Write("testdata.txt", actual, 0644)
actual = expected
}
if expected != actual {
t.Errorf("Expected %s, got %s", expected, actual)
}
}
To print the struct as JSON:
fmt.Printf("%#v\n", yourProject)
Also possible with (as it was mentioned above):
fmt.Printf("%+v\n", yourProject)
But the second option prints string values without "" so it is harder to read.
I suggest u use fmt.Printf("%#v\n", s) , It will print golang type at the same time
package main
import (
"fmt"
"testing"
)
type student struct {
id int32
name string
}
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
}
func TestPrint(t *testing.T) {
s := Project{1, "title","jack"}
fmt.Printf("%+v\n", s)
fmt.Printf("%#v\n", s)
}
result:
{Id:1 Title:title Name:jack}
main.Project{Id:1, Title:"title", Name:"jack"}
You can do the json mashal first and print it as a string. There you can see it the whole struct value completely.
package main
import "fmt"
import "json"
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
}
func main() {
o := Project{Id: 4, Name: "hello", Title: "world"}
om, _ := json.marshal(o)
log.Printf("%s\n", string(om))
}
When you have more complex structures, you might need to convert to JSON before printing:
// Convert structs to JSON.
data, err := json.Marshal(myComplexStruct)
fmt.Printf("%s\n", data)
Source: https://gist.github.com/tetsuok/4942960
Sometimes, it might be handy to print the struct as valid Go code (the go/ast equivalent). For this purpose, https://github.com/hexops/valast does a great job:
package main
import (
"fmt"
"github.com/hexops/valast"
)
type ProjectData struct {
Title string `json:"title"`
Name string `json:"name"`
Data string `json:"data"`
Commits string `json:"commits"`
}
type Project struct {
Id int64 `json:"project_id"`
Data *ProjectData `json:"data"`
}
func main() {
p := Project{
Id: 1,
Data: &ProjectData{
Title: "Test",
Name: "Mihai",
Data: "Some data",
Commits: "Test Message",
},
}
fmt.Println(valast.String(p))
}
Output:
go run main.go
Project{Id: 1, Data: &ProjectData{
Title: "Test",
Name: "Mihai",
Data: "Some data",
Commits: "Test Message",
}}
Visit here to see the complete code. Here you will also find a link for an online terminal where the complete code can be run and the program represents how to extract structure's information(field's name their type & value). Below is the program snippet that only prints the field names.
package main
import "fmt"
import "reflect"
func main() {
type Book struct {
Id int
Name string
Title string
}
book := Book{1, "Let us C", "Enjoy programming with practice"}
e := reflect.ValueOf(&book).Elem()
for i := 0; i < e.NumField(); i++ {
fieldName := e.Type().Field(i).Name
fmt.Printf("%v\n", fieldName)
}
}
/*
Id
Name
Title
*/
Maybe this shouldn't be applied for production requests but if you are on debugging mode I suggest you follow the below approach.
marshalledText, _ := json.MarshalIndent(inputStruct, "", " ")
fmt.Println(string(marshalledText))
This results in formatting the data in json format with increased readability.
i suggest to use json.Unmarshal()
i try to print the id with this hope its helpfull:
var jsonString = `{"Id": 1, "Title": "the title", "Name": "the name","Data": "the data","Commits" : "the commits"}`
var jsonData = []byte(jsonString)
var data Project
var err = json.Unmarshal(jsonData, &data)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("Id :", data.Id)
There's also go-render, which handles pointer recursion and lots of key sorting for string and int maps.
Installation:
go get github.com/luci/go-render/render
Example:
type customType int
type testStruct struct {
S string
V *map[string]int
I interface{}
}
a := testStruct{
S: "hello",
V: &map[string]int{"foo": 0, "bar": 1},
I: customType(42),
}
fmt.Println("Render test:")
fmt.Printf("fmt.Printf: %#v\n", a)))
fmt.Printf("render.Render: %s\n", Render(a))
Which prints:
fmt.Printf: render.testStruct{S:"hello", V:(*map[string]int)(0x600dd065), I:42}
render.Render: render.testStruct{S:"hello", V:(*map[string]int){"bar":1, "foo":0}, I:render.customType(42)}
fmt.Printf("%+v\n", project)
This is the basic way of printing the details
You don't even need the verb. This dumps everything inside of data:
fmt.Println(data)
very simple
I don't have the structure of Data and Commits So I changed the
package main
import (
"fmt"
)
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data string `json:"data"`
Commits string `json:"commits"`
}
func main() {
p := Project{
1,
"First",
"Ankit",
"your data",
"Commit message",
}
fmt.Println(p)
}
For learning you can take help from here : https://gobyexample.com/structs
If you want to write in a log file, as I was searching previously. Then you should use:
log.Infof("Information %+v", structure)
Note:: This will not work with log.Info or log.Debug. In this case, "%v" will get printed, and all the values of the structure will be printed without printing the key/variable name.
A lot of answers for a simple question. I might as well throw my hat in the ring.
package main
import "fmt"
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
//Data Data `json:"data"`
//Commits Commits `json:"commits"`
}
var (
Testy Project
)
func dump_project(foo Project) {
fmt.Println("== Dump Project Struct ====")
fmt.Printf("Id: %d\n", foo.Id)
fmt.Println("Title: ", foo.Title)
fmt.Printf("Name: %v\n", foo.Name)
}
func main() {
fmt.Println("hello from go")
Testy.Id = 3
Testy.Title = "yo"
Testy.Name = "my name"
fmt.Println(Testy)
dump_project(Testy)
}
The output of the various print methods
hello from go
{3 yo my name}
== Dump Project Struct ====
Id: 3
Title: yo
Name: my name
Without using external libraries and with new line after each field:
log.Println(
strings.Replace(
fmt.Sprintf("%#v", post), ", ", "\n", -1))
type Response struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func PostsGet() gin.HandlerFunc {
return func(c *gin.Context) {
xs, err := http.Get("https://jsonplaceholder.typicode.com/posts")
if err != nil {
log.Println("The HTTP request failed with error: ", err)
}
data, _ := ioutil.ReadAll(xs`enter code here`.Body)
// this will print the struct in console
fmt.Println(string(data))
// this is to send as response for the API
bytes := []byte(string(data))
var res []Response
json.Unmarshal(bytes, &res)
c.JSON(http.StatusOK, res)
}
}
Another way is, create a func called toString that takes struct, format the
fields as you wish.
import (
"fmt"
)
type T struct {
x, y string
}
func (r T) toString() string {
return "Formate as u need :" + r.x + r.y
}
func main() {
r1 := T{"csa", "ac"}
fmt.Println("toStringed : ", r1.toString())
}
Most of these packages are relying on the reflect package to make such things possible.
fmt.Sprintf() is using -> func (p *pp) printArg(arg interface{}, verb rune) of standard lib
Go to line 638 -> https://golang.org/src/fmt/print.go
Reflection:
https://golang.org/pkg/reflect/
Example code:
https://github.com/donutloop/toolkit/blob/master/debugutil/prettysprint.go
fmt.Println("%+v", structure variable)
A better way to do this would be to create a global constant for the string "%+v" in a package called "commons"(maybe) and use it everywhere in your code
//In commons package
const STRUCTURE_DATA_FMT = "%+v"
//In your code everywhere
fmt.Println(commons.STRUCTURE_DATA_FMT, structure variable)

Resources