Last active
July 3, 2024 21:11
-
-
Save hartfordfive/69f84657267c2327e484 to your computer and use it in GitHub Desktop.
Go function to center a string with whitespace padding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
) | |
// Example: http://play.golang.org/p/Q34HEmWMXh | |
func main() { | |
fmt.Printf("|%s|%s|%s|%s|\n", | |
centerString("First Name", 20), | |
centerString("Last Name", 20), | |
centerString("DOB", 20), | |
centerString("Country", 22)) | |
fmt.Println("----------------------------------------------------------------------------------------") | |
fmt.Printf("|%s|%s|%s|%s|\n", | |
centerString("John", 20), | |
centerString("Doe", 20), | |
centerString("July 15, 1975", 20), | |
centerString("United States", 22)) | |
} | |
func centerString(str string, total_field_width int) string { | |
str_len := len(str) | |
spaces_to_pad := total_field_width - str_len | |
var tmp_spaces float64 | |
var lr_spaces int | |
tmp_spaces = float64(spaces_to_pad) / 2 | |
lr_spaces = int(tmp_spaces) | |
buffer := bytes.NewBufferString("") | |
spaces_remaining := total_field_width | |
for i := 0; i < lr_spaces; i++ { | |
buffer.WriteString(" ") | |
spaces_remaining = spaces_remaining - 1 | |
} | |
buffer.WriteString(str) | |
spaces_remaining = spaces_remaining - str_len | |
for i := spaces_remaining; i > 0; i-- { | |
buffer.WriteString(" ") | |
} | |
return buffer.String() | |
} |
I initially thought @tanema 's solution would be slower, but then I checked it and it's actually much faster for "medium" widths, though a bit slower for very small ones!
I came up with a solution that works using just a format string, but that's a bit slower as well:
func centerString(s string, width int) string {
a := (width - len(s)) / 2
b := a + len(s)
if width % 2 != 0 {
a++
}
return fmt.Sprintf("%[1]*[3]s%[2]*[4]s", b, a, s, "")
}
As I will use this function on a logger handler, I wanted it to be fast... also, I was just curious, so I wrote a quick benchmark:
package test
import (
"bytes"
"fmt"
"strings"
"testing"
)
var result interface{}
func centerString1(str string, total_field_width int) string {
str_len := len(str)
spaces_to_pad := total_field_width - str_len
var tmp_spaces float64
var lr_spaces int
tmp_spaces = float64(spaces_to_pad) / 2
lr_spaces = int(tmp_spaces)
buffer := bytes.NewBufferString("")
spaces_remaining := total_field_width
for i := 0; i < lr_spaces; i++ {
buffer.WriteString(" ")
spaces_remaining = spaces_remaining - 1
}
buffer.WriteString(str)
spaces_remaining = spaces_remaining - str_len
for i := spaces_remaining; i > 0; i-- {
buffer.WriteString(" ")
}
return buffer.String()
}
func centerString2(str string, width int) string {
spaces := int(float64(width-len(str)) / 2)
return strings.Repeat(" ", spaces) + str + strings.Repeat(" ", width-(spaces+len(str)))
}
func centerString3(s string, width int) string {
a := (width - len(s)) / 2
b := a + len(s)
if width % 2 != 0 {
a++
}
return fmt.Sprintf("%[1]*[3]s%[2]*[4]s", b, a, s, "")
}
func benchmarkCenterString1(b *testing.B, w int, s string) {
var r interface{}
for n := 0; n < b.N; n++ {
r = centerString1(s, w)
}
result = r
}
func benchmarkCenterString2(b *testing.B, w int, s string) {
var r interface{}
for n := 0; n < b.N; n++ {
r = centerString2(s, w)
}
result = r
}
func benchmarkCenterString3(b *testing.B, w int, s string) {
var r interface{}
for n := 0; n < b.N; n++ {
r = centerString3(s, w)
}
result = r
}
func Benchmark1CenterString2(b *testing.B) { benchmarkCenterString1(b, 2, "a") }
func Benchmark1CenterString10(b *testing.B) { benchmarkCenterString1(b, 10, "abc") }
func Benchmark1CenterString100(b *testing.B) { benchmarkCenterString1(b, 100, "abc") }
func Benchmark1CenterString1000(b *testing.B) { benchmarkCenterString1(b, 1000, "abc") }
func Benchmark1CenterString1000L(b *testing.B) { benchmarkCenterString1(b, 1000, "abcdefghijklmnopqrstuvxzwyabcdefghijklmnopqrstuvxzwyabcdefghijklmnopqrstuvxzwy") }
func Benchmark2CenterString2(b *testing.B) { benchmarkCenterString2(b, 2, "a") }
func Benchmark2CenterString10(b *testing.B) { benchmarkCenterString2(b, 10, "abc") }
func Benchmark2CenterString100(b *testing.B) { benchmarkCenterString2(b, 100, "abc") }
func Benchmark2CenterString1000(b *testing.B) { benchmarkCenterString2(b, 1000, "abc") }
func Benchmark2CenterString1000L(b *testing.B) { benchmarkCenterString2(b, 1000, "abcdefghijklmnopqrstuvxzwyabcdefghijklmnopqrstuvxzwyabcdefghijklmnopqrstuvxzwy") }
func Benchmark3CenterString2(b *testing.B) { benchmarkCenterString3(b, 2, "a") }
func Benchmark3CenterString10(b *testing.B) { benchmarkCenterString3(b, 10, "abc") }
func Benchmark3CenterString100(b *testing.B) { benchmarkCenterString3(b, 100, "abc") }
func Benchmark3CenterString1000(b *testing.B) { benchmarkCenterString3(b, 1000, "abc") }
func Benchmark3CenterString1000L(b *testing.B) { benchmarkCenterString3(b, 1000, "abcdefghijklmnopqrstuvxzwyabcdefghijklmnopqrstuvxzwyabcdefghijklmnopqrstuvxzwy") }
Results on my Macbook Air:
goos: darwin
goarch: amd64
pkg: server/test
cpu: Intel(R) Core(TM) i5-1030NG7 CPU @ 1.10GHz
# Original Solution
Benchmark1CenterString2-8 18358189 59.52 ns/op
Benchmark1CenterString10-8 12077696 100.3 ns/op
Benchmark1CenterString100-8 1727518 682.5 ns/op
Benchmark1CenterString1000-8 196567 5699 ns/op
Benchmark1CenterString1000L-8 215280 5540 ns/op
# Tanema's Solution
Benchmark2CenterString2-8 16654598 70.01 ns/op
Benchmark2CenterString10-8 8091330 153.4 ns/op
Benchmark2CenterString100-8 4972375 255.4 ns/op
Benchmark2CenterString1000-8 1410862 820.8 ns/op
Benchmark2CenterString1000L-8 1358682 812.8 ns/op
# My Solution
Benchmark3CenterString2-8 4882995 238.0 ns/op
Benchmark3CenterString10-8 4467850 286.1 ns/op
Benchmark3CenterString100-8 2866339 404.3 ns/op
Benchmark3CenterString1000-8 1000000 1109 ns/op
Benchmark3CenterString1000L-8 1215786 956.0 ns/op
PASS
ok server/test 24.125s
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This could be simplified a lot: https://go.dev/play/p/ptjC-dj6iMQ