Skip to content

Commit

Permalink
feat: str - add more padding util functions
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Nov 26, 2022
1 parent 71fc27a commit 55b0e17
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 160 deletions.
40 changes: 40 additions & 0 deletions group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package goutil_test

import (
"fmt"
"net/http"
"testing"
"time"

"github.com/gookit/goutil"
"github.com/gookit/goutil/netutil/httpreq"
"github.com/gookit/goutil/testutil/assert"
)

func TestNewErrGroup(t *testing.T) {
httpreq.ConfigStd(func(hc *http.Client) {
hc.Timeout = 3 * time.Second
})

eg := goutil.NewErrGroup()
eg.Add(func() error {
resp, err := httpreq.Get("https://httpbin.org/get", nil)
if err != nil {
return err
}

fmt.Println(resp.Body)
return nil
}, func() error {
resp, err := httpreq.Post("https://httpbin.org/post", "hi", nil)
if err != nil {
return err
}

fmt.Println(resp.Body)
return nil
})

err := eg.Wait()
assert.NoErr(t, err)
}
168 changes: 168 additions & 0 deletions strutil/padding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package strutil

import (
"fmt"
"strings"
)

// PosFlag type
type PosFlag uint8

// Position for padding/resize string
const (
PosLeft PosFlag = iota
PosRight
PosMiddle
)

/*************************************************************
* String padding operation
*************************************************************/

// Padding a string.
func Padding(s, pad string, length int, pos PosFlag) string {
diff := len(s) - length
if diff >= 0 { // do not need padding.
return s
}

if pad == "" || pad == " " {
mark := ""
if pos == PosRight { // to right
mark = "-"
}

// padding left: "%7s", padding right: "%-7s"
tpl := fmt.Sprintf("%s%d", mark, length)
return fmt.Sprintf(`%`+tpl+`s`, s)
}

if pos == PosRight { // to right
return s + Repeat(pad, -diff)
}
return Repeat(pad, -diff) + s
}

// PadLeft a string.
func PadLeft(s, pad string, length int) string {
return Padding(s, pad, length, PosLeft)
}

// PadRight a string.
func PadRight(s, pad string, length int) string {
return Padding(s, pad, length, PosRight)
}

// Resize a string by given length and align settings. padding space.
func Resize(s string, length int, align PosFlag) string {
diff := len(s) - length
if diff >= 0 { // do not need padding.
return s
}

if align == PosMiddle {
strLn := len(s)
padLn := (length - strLn) / 2
padStr := string(make([]byte, padLn, padLn))

if diff := length - padLn*2; diff > 0 {
s += " "
}
return padStr + s + padStr
}

return Padding(s, " ", length, align)
}

// PadChars padding a rune/byte to want length and with position flag
func PadChars[T byte | rune](cs []T, pad T, length int, pos PosFlag) []T {
ln := len(cs)
if ln >= length {
ns := make([]T, length)
copy(ns, cs[:length])
return ns
}

idx := length - ln
ns := make([]T, length)
ps := RepeatChars(pad, idx)
if pos == PosRight {
copy(ns, cs)
copy(ns[idx:], ps)
} else { // to left
copy(ns[:idx], ps)
copy(ns[idx:], cs)
}

return ns
}

// PadBytes padding a byte to want length and with position flag
func PadBytes(bs []byte, pad byte, length int, pos PosFlag) []byte {
return PadChars(bs, pad, length, pos)
}

// PadBytesLeft a byte to want length
func PadBytesLeft(bs []byte, pad byte, length int) []byte {
return PadChars(bs, pad, length, PosLeft)
}

// PadBytesRight a byte to want length
func PadBytesRight(bs []byte, pad byte, length int) []byte {
return PadChars(bs, pad, length, PosRight)
}

// PadRunes padding a rune to want length and with position flag
func PadRunes(rs []rune, pad rune, length int, pos PosFlag) []rune {
return PadChars(rs, pad, length, pos)
}

// PadRunesLeft a rune to want length
func PadRunesLeft(rs []rune, pad rune, length int) []rune {
return PadChars(rs, pad, length, PosLeft)
}

// PadRunesRight a rune to want length
func PadRunesRight(rs []rune, pad rune, length int) []rune {
return PadChars(rs, pad, length, PosRight)
}

/*************************************************************
* String repeat operation
*************************************************************/

// Repeat a string
func Repeat(s string, times int) string {
if times <= 0 {
return ""
}
if times == 1 {
return s
}

ss := make([]string, 0, times)
for i := 0; i < times; i++ {
ss = append(ss, s)
}

return strings.Join(ss, "")
}

// RepeatRune repeat a rune char.
func RepeatRune(char rune, times int) []rune {
return RepeatChars(char, times)
}

// RepeatBytes repeat a byte char.
func RepeatBytes(char byte, times int) []byte {
return RepeatChars(char, times)
}

// RepeatChars repeat a byte char.
func RepeatChars[T byte | rune](char T, times int) []T {
chars := make([]T, 0, times)
for i := 0; i < times; i++ {
chars = append(chars, char)
}
return chars
}
100 changes: 100 additions & 0 deletions strutil/padding_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package strutil_test

import (
"testing"

"github.com/gookit/goutil/strutil"
"github.com/gookit/goutil/testutil/assert"
)

func TestPadding(t *testing.T) {
tests := []struct {
want, give, pad string
len int
pos strutil.PosFlag
}{
{"ab000", "ab", "0", 5, strutil.PosRight},
{"000ab", "ab", "0", 5, strutil.PosLeft},
{"ab012", "ab012", "0", 4, strutil.PosLeft},
{"ab ", "ab", "", 5, strutil.PosRight},
{" ab", "ab", "", 5, strutil.PosLeft},
}

for _, tt := range tests {
assert.Eq(t, tt.want, strutil.Padding(tt.give, tt.pad, tt.len, tt.pos))

if tt.pos == strutil.PosRight {
assert.Eq(t, tt.want, strutil.PadRight(tt.give, tt.pad, tt.len))
} else {
assert.Eq(t, tt.want, strutil.PadLeft(tt.give, tt.pad, tt.len))
}
}
}

func TestRepeat(t *testing.T) {
assert.Eq(t, "aaa", strutil.Repeat("a", 3))
assert.Eq(t, "DD", strutil.Repeat("D", 2))
assert.Eq(t, "D", strutil.Repeat("D", 1))
assert.Eq(t, "", strutil.Repeat("0", 0))
assert.Eq(t, "", strutil.Repeat("D", -3))
}

func TestRepeatRune(t *testing.T) {
tests := []struct {
want []rune
give rune
times int
}{
{[]rune("bbb"), 'b', 3},
{[]rune("..."), '.', 3},
{[]rune(" "), ' ', 2},
}

for _, tt := range tests {
assert.Eq(t, tt.want, strutil.RepeatRune(tt.give, tt.times))
}
}

func TestRepeatBytes(t *testing.T) {
assert.Eq(t, []byte("aaa"), strutil.RepeatBytes('a', 3))
}

func TestPadChars(t *testing.T) {
tests := []struct {
wt []byte
ls []byte
pad byte
pln int
}{
{
[]byte("aaaabc"), []byte("abc"), 'a', 6,
},
{
[]byte("abc"), []byte("abcd"), 'a', 3,
},
}
for _, item := range tests {
assert.Eq(t, item.wt, strutil.PadChars(item.ls, item.pad, item.pln, strutil.PosLeft))
assert.Eq(t, item.wt, strutil.PadBytes(item.ls, item.pad, item.pln, strutil.PosLeft))
assert.Eq(t, item.wt, strutil.PadBytesLeft(item.ls, item.pad, item.pln))
}

tests2 := []struct {
wt []byte
ls []byte
pad byte
pln int
}{
{
[]byte("abcaaa"), []byte("abc"), 'a', 6,
},
{
[]byte("abc"), []byte("abcd"), 'a', 3,
},
}
for _, item := range tests2 {
assert.Eq(t, item.wt, strutil.PadChars(item.ls, item.pad, item.pln, strutil.PosRight))
assert.Eq(t, item.wt, strutil.PadBytes(item.ls, item.pad, item.pln, strutil.PosRight))
assert.Eq(t, item.wt, strutil.PadBytesRight(item.ls, item.pad, item.pln))
}
}
Loading

0 comments on commit 55b0e17

Please sign in to comment.