Golang Escape Variables with Printf

When working with Go (Golang) native fmt.Printf or fmt.Sprintf methods, there are edge cases you have to be aware of when formatting strings. In this article we are going to see how you can escape percent sign in your Go strings when using Printf methods. In our example we have a set of strings which we want to print and format based on our given layout. However, the layout contains itself a percent sign, which is used for specifying where your value will be placed in your layout string. Let’s have a look at the example so you can see clearly.

package main

import (
    "fmt"
)

func main() {
    message := "We produce 100% organic %s\n" // eg. We produce 100% organic fish
    foods := []string{"vegetables", "fruit", "meat", "fish"}
    for _, food := range foods {
        fmt.Printf(message, food)
    }
}

The objective is to have the same layout for all string values (vegs, fruits, meat, fish in this case). This example however does not work properly. This is the expected output from the above snippet. You can also run it by yourself by following the Golang Playground link https://play.golang.org/p/hCPiAT9FVaK

We produce 100%!o(string=vegetables)rganic %!s(MISSING)
We produce 100%!o(string=fruit)rganic %!s(MISSING)
We produce 100%!o(string=meat)rganic %!s(MISSING)
We produce 100%!o(string=fish)rganic %!s(MISSING)

How to escape the percent sign in fmt.Printf

This is due to the fact that each food is erronously inserted when the first percent sign is encountered. In order for us to tell fmt.Printf to ignore the first percent sign, we need to explicitely escape that in our layout string. Please check the documentation of fmt.Printf https://pkg.go.dev/fmt

Please use %% ‘double percent’ for literal % ‘percent’ sign

%%  a literal percent sign; consumes no value

After having fixed our layout string, the example above looks like this

package main

import (
    "fmt"
)

func main() {
    message := "We produce 100%% organic %s\n"
    foods := []string{"vegetables", "fruit", "meat", "fish"}
    for _, food := range foods {
        fmt.Printf(message, food)
    }
}

You can run the code by yourself by going to the Golang Playground https://play.golang.org/p/ZUZVpASpCYD

The expected output now, matches our expected strings

We produce 100% organic vegetables
We produce 100% organic fruit
We produce 100% organic meat
We produce 100% organic fish
Join the Golang Developers Community on Golang Cafe