Golang: How to pad a number with zeros when printing?

Go

Go 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

link : https://play.golang.org/p/25g3L8TXiPP

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
}

https://pkg.go.dev/golang.org/x/text/number

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()
}

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTravis ReederView Question on Stackoverflow
Solution 1 - GoTravis ReederView Answer on Stackoverflow
Solution 2 - GoChristopher OezbekView Answer on Stackoverflow
Solution 3 - GoJai PrakView Answer on Stackoverflow
Solution 4 - GoVonCView Answer on Stackoverflow
Solution 5 - GoULLAS KView Answer on Stackoverflow
Solution 6 - GokeyziView Answer on Stackoverflow
Solution 7 - GoGillespieView Answer on Stackoverflow
Solution 8 - GoInductionView Answer on Stackoverflow
Solution 9 - GoZomboView Answer on Stackoverflow
Solution 10 - GoChanceView Answer on Stackoverflow