Golang: How to pad a number with zeros when printing?
GoGo Problem Overview
How can I print a number or make a string with zero padding to make it fixed width?
For instance, if I have the number 12
and I want to make it 000012
.
Go Solutions
Solution 1 - Go
The fmt package can do this for you:
fmt.Printf("|%06d|%6d|\n", 12, 345)
Output:
|000012| 345|
Notice the 0 in %06d, that will make it a width of 6 and pad it with zeros. The second one will pad with spaces.
Try it for yourself here: http://play.golang.org/p/cinDspMccp
Solution 2 - Go
Use the Printf
function from the fmt package with a width
of 6
and the padding character 0
:
import "fmt"
fmt.Printf("%06d", 12) // Prints to stdout '000012'
Setting the width works by putting an integer directly preceding the format specifier ('verb'):
fmt.Printf("%d", 12) // Uses default width, prints '12'
fmt.Printf("%6d", 12) // Uses a width of 6 and left pads with spaces, prints ' 12'
The only padding characters supported by Golang (and most other languages) are spaces and 0
:
fmt.Printf("%6d", 12) // Default padding is spaces, prints ' 12'
fmt.Printf("%06d", 12) // Change to 0 padding, prints '000012'
It is possible to right-justify the printing by prepending a minus -
:
fmt.Printf("%-6d", 12) // Padding right-justified, prints '12 '
Beware that for floating point numbers the width includes the whole format string:
fmt.Printf("%06.1f", 12.0) // Prints '0012.0' (width is 6, precision is 1 digit)
It is useful to note that the width can also be set programmatically by using *
instead of a number and passing the width as an int
parameter:
myWidth := 6
fmt.Printf("%0*d", myWidth, 12) // Prints '000012' as before
This might be useful for instance if the largest value you want to print is only known at runtime (called maxVal
in the following example):
myWidth := 1 + int(math.Log10(float64(maxVal)))
fmt.Printf("%*d", myWidth, nextVal)
Last, if you don't want to print to stdout
but return a String, use Sprintf
also from fmt package with the same parameters:
s := fmt.Sprintf("%06d", 12) // returns '000012' as a String
Solution 3 - Go
There is one simplest way to achieve this. Use
func padNumberWithZero(value uint32) string {
return fmt.Sprintf("%02d", value)
}
fmt.Sprintf
formats and returns a string without printing it anywhere.
Here %02d
says pad zero on left for value who has < 2 number of digits. If given value has 2 or more digits it will not pad. For example:
- If input is 1, output will be 01.
- If input is 12, output will be 12.
- If input is 1992, output will be 1992.
You can use %03d
or more for more zeros padding.
Solution 4 - Go
The question "List of printing format in Go lang" reminds us that there is also the flag:
> -
pad with spaces on the right rather than the left (left-justify the field)
You can see more padding examples with DaddyOh/golang-samples/pad.go
, if you want to pad with other string sequences (more complex than '0
' or '
'):
leftPad(s string, padStr string, pLen int)
rightPad(s string, padStr string, pLen int)
leftPad2Len(s string, padStr string, overallLen int)
rightPad2Len(s string, padStr string, overallLen int)
See play.golang.org:
1234567890
leftPad(str, "*", 3) ***1234567890
leftPad2Len(str, "*-", 13) -*-1234567890
leftPad2Len(str, "*-", 14) *-*-1234567890
leftPad2Len(str, "*", 14) ****1234567890
leftPad2Len(str, "*-x", 14) x*-x1234567890
leftPad2Len(str, "ABCDE", 14) BCDE1234567890
leftPad2Len(str, "ABCDE", 4) 7890
rightPad(str, "*", 3) 1234567890***
rightPad(str, "*!", 3) 1234567890*!*!*!
rightPad2Len(str, "*-", 13) 1234567890*-*
rightPad2Len(str, "*-", 14) 1234567890*-*-
rightPad2Len(str, "*", 14) 1234567890****
rightPad2Len(str, "*-x", 14) 1234567890*-x*
rightPad2Len(str, "ABCDE", 14) 1234567890ABCD
rightPad2Len(str, "ABCDE", 4) 1234
Solution 5 - Go
Just in case if you want to prefix or suffix to form another word by concatenating you can use below code.
package main
import "fmt"
func main() {
concatenatedWord:= "COUNTER_"+fmt.Sprintf("%02d", 1)
// use concatenatedWord
fmt.Println("ConcatenatedWordword is", concatenatedWord)
}
output : ConcatenatedWordword is COUNTER_01
Solution 6 - Go
func lpad(s string,pad string, plength int)string{
for i:=len(s);i<plength;i++{
s=pad+s
}
return s
}
lpad("3","0",2) result: "03"
lpad("12","0",6) result: "000012"
Solution 7 - Go
Here's my solution:
func leftZeroPad(number, padWidth int64) string {
return fmt.Sprintf(fmt.Sprintf("%%0%dd", padWidth), number)
}
Example usage:
fmt.Printf("%v", leftZeroPad(12, 10))
prints:
0000000012
The advantage of this is that you can specify the pad length at run time if needed.
Solution 8 - Go
For those that want to right pad, you can do this:
str2pad := "12"
padWith := "0"
amt2pad := 6
//This will make sure there is always 6 characters total, padded on the right side
//Note to check if strings.Repeat returns a negative value
paddedStr := str2pad + strings.Repeat(padWith, amt2pad - len(str2pad))
//Outputs 120000
Solution 9 - Go
Another option is the golang.org/x/text/number
package:
package main
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/number"
)
var fmt = message.NewPrinter(language.English)
func main() {
n := number.Decimal(
12, number.Pad('0'), number.FormatWidth(6),
)
fmt.Println(n) // 000012
}
Solution 10 - Go
The math approach:
func padLeft(v int64, length int) string {
abs := math.Abs(float64(v))
var padding int
if v != 0 {
min := math.Pow10(length - 1)
if min-abs > 0 {
l := math.Log10(abs)
if l == float64(int64(l)) {
l++
}
padding = length - int(math.Ceil(l))
}
} else {
padding = length - 1
}
builder := strings.Builder{}
if v < 0 {
length = length + 1
}
builder.Grow(length * 4)
if v < 0 {
builder.WriteRune('-')
}
for i := 0; i < padding; i++ {
builder.WriteRune('0')
}
builder.WriteString(strconv.FormatInt(int64(abs), 10))
return builder.String()
}
Example:
package main
import (
"fmt"
"math"
"strconv"
"strings"
)
func main() {
v := padLeft(0, 10)
fmt.Println(v, "length:", len(v), "expected (10)")
// 0000000000 length: 10 expected (10)
v = padLeft(5, 10)
fmt.Println(v, "length:", len(v), "expected (10)")
// 0000000005 length: 10 expected (10)
v = padLeft(12345, 10)
fmt.Println(v, "length:", len(v), "expected (10)")
// 0000012345 length: 10 expected (10)
v = padLeft(333, 6)
fmt.Println(v, "length:", len(v), "expected (6)")
// 000333 length: 6 expected (6)
v = padLeft(1, 10)
fmt.Println(v, "length:", len(v), "expected (10)")
// 0000000001 length: 10 expected (10)
v = padLeft(12345, 4)
fmt.Println(v, "length:", len(v), "expected (5)")
// 12345 length: 5 expected (5)
v = padLeft(3, 4)
fmt.Println(v, "length:", len(v), "expected (4)")
// 0003 length: 4 expected (4)
v = padLeft(-3, 4)
fmt.Println(v, "length:", len(v), "expected (5)")
// -0003 length: 5 expected (5)
}
func padLeft(v int64, length int) string {
abs := math.Abs(float64(v))
var padding int
if v != 0 {
min := math.Pow10(length - 1)
if min-abs > 0 {
l := math.Log10(abs)
if l == float64(int64(l)) {
l++
}
padding = length - int(math.Ceil(l))
}
} else {
padding = length -1
}
builder := strings.Builder{}
if v < 0 {
length = length + 1
}
builder.Grow(length * 4)
if v < 0 {
builder.WriteRune('-')
}
for i := 0; i < padding; i++ {
builder.WriteRune('0')
}
builder.WriteString(strconv.FormatInt(int64(abs), 10))
return builder.String()
}
Playground Link
https://play.golang.org/p/1gFUtMUQDlM
Benchmarks
Using a slightly modified version, because my values are always positive:
// Random is basically just a rand.Rand in this case
func (r Random) codeWithFmt(length int) string {
max := int64(math.Pow10(length)) - 1
var v int64
for v == 0 {
v = r.Int63n(max)
}
return fmt.Sprintf("%0*d", length, v)
}
func (r Random) Code(digits int) string {
max := int64(math.Pow10(digits)) - 1
var v int64
for v == 0 {
v = r.Int63n(max)
}
var padding int
if math.Pow10(digits-1)-float64(v) > 0 {
lv := math.Log10(float64(v))
if lv == float64(int64(lv)) {
lv++
}
padding = digits - int(math.Ceil(lv))
}
builder := strings.Builder{}
builder.Grow(digits * 4)
for i := 0; i < padding; i++ {
builder.WriteRune('0')
}
builder.WriteString(strconv.FormatInt(v, 10))
return builder.String()
}
func BenchmarkCodeGeneration(b *testing.B) {
assert := require.New(b)
_ = assert
r := New()
for i := 0; i < b.N; i++ {
// assert.Len(r.Code(7), 7)
r.Code(7)
}
}
func BenchmarkCodeGenerationWithFmt(b *testing.B) {
assert := require.New(b)
_ = assert
r := New()
for i := 0; i < b.N; i++ {
// assert.Len(r.codeWithFmt(7), 7)
r.codeWithFmt(7)
}
}
Benchmark Results
BenchmarkCodeGeneration
BenchmarkCodeGeneration-8 5219466 204.8 ns/op 56 B/op 3 allocs/op
BenchmarkCodeGenerationWithFmt
BenchmarkCodeGenerationWithFmt-8 4306922 283.9 ns/op 32 B/op 4 allocs/op