Patrick
Patrick

Reputation: 3021

How to ignore extra fields for fmt.Sprintf

I have a Golang program that reads a string parameter from command line and passes it to the fmt.Sprintf function. Let's say tmp_str is the target string from command line.

package main

import "fmt"

func main() {
    tmp_str := "hello %s"
    str := fmt.Sprintf(tmp_str, "world")
    fmt.Println(str)
}

In some cases, the program will pass a completed string like "Hello Friends", instead of a string template.. The program would panic and return:

Hello Friends%!(EXTRA string=world)

So, how to ignore the extra fields for fmt.Sprintf?

Upvotes: 11

Views: 10648

Answers (5)

32f
32f

Reputation: 101

I use this one (which can probably be expanded on)

Sprintf("Hello"+"%[2]s", "World", "")
Sprintf("Hello %s"+"%[2]s", "World", "")

Upvotes: 0

Stein
Stein

Reputation: 1639

In this particular case, you could require the command line users to always supply a %s verb, and explain they can truncate the string to zero length:

Hello Friends%.0s

or even shorter:

Hello Friends%.s

The output is plain:

Hello Friends

Upvotes: 11

Denys Séguret
Denys Séguret

Reputation: 382404

Yes you can do it, by slicing the arguments you pass to the variadic Sprintf function:

func TruncatingSprintf(str string, args ...interface{}) (string, error) {
    n := strings.Count(str, "%s")
    if n > len(args) {
        return "", errors.New("Unexpected string:" + str)
    }
    return fmt.Sprintf(str, args[:n]...), nil
}

func main() {
    tmp_str := "hello %s %s %s"         // don't hesitate to add many %s here
    str, err := TruncatingSprintf(tmp_str, "world") // or many arguments here
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(str)
}

Demonstration 1

Demonstration 2 (a different version outputting even when there's more %s than arguments)

But you don't usually use dynamic formatted strings, this isn't secure and if you want to accept any string, you should also adapt this code to no choke on %%s. If you venture this far, then you should probably have a look at templates (which would let you use named strings, and thus the missing one wouldn't have to be the last one).

Upvotes: 9

alex vasi
alex vasi

Reputation: 5344

I agree with Volker's answer, but you could check your input string:

package main

import (
    "fmt"
    "strings"
)

func main() {
    tmp_str := "hello %s"

    res := tmp_str
    if strings.Count(tmp_str, "%s") == 1 {
        res = fmt.Sprintf(tmp_str, "world")
    }
    fmt.Println(res)
}

Upvotes: 4

Volker
Volker

Reputation: 42458

You cannot do this.

You have to find a different solution.

Upvotes: -8

Related Questions