-
Notifications
You must be signed in to change notification settings - Fork 191
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: str - add more padding util functions
- Loading branch information
Showing
5 changed files
with
309 additions
and
160 deletions.
There are no files selected for viewing
This file contains 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
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) | ||
} |
This file contains 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
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 | ||
} |
This file contains 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
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)) | ||
} | ||
} |
Oops, something went wrong.