diff --git a/docs/strutil.md b/docs/strutil.md index cc42660..5c27c56 100644 --- a/docs/strutil.md +++ b/docs/strutil.md @@ -44,6 +44,13 @@ import ( - [SplitEx](#SplitEx) - [SplitWords](#SplitWords) - [WordCount](#WordCount) +- [RemoveNonPrintable](#RemoveNonPrintable) +- [StringToBytes](#StringToBytes) +- [BytesToString](#BytesToString) +- [IsBlank](#IsBlank) +- [HasPrefixAny](#HasPrefixAny) +- [HasSuffixAny](#HasSuffixAny) +- [IndexOffset](#IndexOffset)
@@ -823,3 +830,195 @@ func main() { // 0 } ``` + +### StringToBytes + +

Converts a string to byte slice without a memory allocation.

+ +Signature: + +```go +func StringToBytes(str string) (b []byte) +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.StringToBytes("abc") + result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'}) + + fmt.Println(result1) + fmt.Println(result2) + // Output: + // [97 98 99] + // true +} +``` + +### BytesToString + +

Converts a byte slice to string without a memory allocation.

+ +Signature: + +```go +func BytesToString(bytes []byte) string +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + bytes := []byte{'a', 'b', 'c'} + result := strutil.BytesToString(bytes) + + fmt.Println(result) + // Output: + // abc +} +``` + +### IsBlank + +

Checks if a string is whitespace or empty.

+ +Signature: + +```go +func IsBlank(str string) bool +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.IsBlank("") + result2 := strutil.IsBlank("\t\v\f\n") + result3 := strutil.IsBlank(" 中文") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + // Output: + // true + // true + // false +} +``` + +### HasPrefixAny + +

Checks if a string starts with any of an array of specified strings.

+ +Signature: + +```go +func HasPrefixAny(str string, prefixes []string) bool +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"}) + result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"}) + + fmt.Println(result1) + fmt.Println(result2) + // Output: + // true + // false +} +``` + +### HasSuffixAny + +

Checks if a string ends with any of an array of specified strings.

+ +Signature: + +```go +func HasSuffixAny(str string, suffixes []string) bool +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"}) + result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"}) + + fmt.Println(result1) + fmt.Println(result2) + // Output: + // true + // false +} +``` + +### IndexOffset + +

Returns the index of the first instance of substr in string after offsetting the string by `idxFrom`, or -1 if substr is not present in string.

+ +Signature: + +```go +func IndexOffset(str string, substr string, idxFrom int) int +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + str := "foo bar hello world" + + result1 := strutil.IndexOffset(str, "o", 5) + result2 := strutil.IndexOffset(str, "o", 0) + result3 := strutil.IndexOffset(str, "d", len(str)-1) + result4 := strutil.IndexOffset(str, "d", len(str)) + result5 := strutil.IndexOffset(str, "f", -1) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + // Output: + // 12 + // 1 + // 18 + // -1 + // -1 +} +``` \ No newline at end of file diff --git a/docs/strutil_zh-CN.md b/docs/strutil_zh-CN.md index 595e64d..c29ec30 100644 --- a/docs/strutil_zh-CN.md +++ b/docs/strutil_zh-CN.md @@ -44,6 +44,13 @@ import ( - [SplitEx](#SplitEx) - [SplitWords](#SplitWords) - [WordCount](#WordCount) +- [RemoveNonPrintable](#RemoveNonPrintable) +- [StringToBytes](#StringToBytes) +- [BytesToString](#BytesToString) +- [IsBlank](#IsBlank) +- [HasPrefixAny](#HasPrefixAny) +- [HasSuffixAny](#HasSuffixAny) +- [IndexOffset](#IndexOffset)
@@ -824,3 +831,226 @@ func main() { // 0 } ``` + + +### RemoveNonPrintable + +

删除字符串中不可打印的字符。

+ +函数签名: + +```go +func RemoveNonPrintable(str string) string +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.RemoveNonPrintable("hello\u00a0 \u200bworld\n") + result2 := strutil.RemoveNonPrintable("你好😄") + + fmt.Println(result1) + fmt.Println(result2) + // Output: + // hello world + // 你好😄 +} +``` + +### StringToBytes + +

在不分配内存的情况下将字符串转换为字节片。

+ +函数签名: + +```go +func StringToBytes(str string) (b []byte) +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.StringToBytes("abc") + result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'}) + + fmt.Println(result1) + fmt.Println(result2) + // Output: + // [97 98 99] + // true +} +``` + +### BytesToString + +

在不分配内存的情况下将字节切片转换为字符串。

+ +函数签名: + +```go +func BytesToString(bytes []byte) string +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + bytes := []byte{'a', 'b', 'c'} + result := strutil.BytesToString(bytes) + + fmt.Println(result) + // Output: + // abc +} +``` + +### IsBlank + +

检查字符串是否为空格或空。

+ +函数签名: + +```go +func IsBlank(str string) bool +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.IsBlank("") + result2 := strutil.IsBlank("\t\v\f\n") + result3 := strutil.IsBlank(" 中文") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + // Output: + // true + // true + // false +} +``` + +### HasPrefixAny + +

检查字符串是否以指定字符串数组中的任何一个开头。

+ +函数签名: + +```go +func HasPrefixAny(str string, prefixes []string) bool +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"}) + result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"}) + + fmt.Println(result1) + fmt.Println(result2) + // Output: + // true + // false +} +``` + +### HasSuffixAny + +

检查字符串是否以指定字符串数组中的任何一个结尾。

+ +函数签名: + +```go +func HasSuffixAny(str string, suffixes []string) bool +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"}) + result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"}) + + fmt.Println(result1) + fmt.Println(result2) + // Output: + // true + // false +} +``` + +### IndexOffset + +

将字符串偏移idxFrom后,返回字符串中第一个 substr 实例的索引,如果字符串中不存在 substr,则返回 -1。

+ +函数签名: + +```go +func IndexOffset(str string, substr string, idxFrom int) int +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + str := "foo bar hello world" + + result1 := strutil.IndexOffset(str, "o", 5) + result2 := strutil.IndexOffset(str, "o", 0) + result3 := strutil.IndexOffset(str, "d", len(str)-1) + result4 := strutil.IndexOffset(str, "d", len(str)) + result5 := strutil.IndexOffset(str, "f", -1) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + // Output: + // 12 + // 1 + // 18 + // -1 + // -1 +} +``` \ No newline at end of file diff --git a/netutil/net_test.go b/netutil/net_test.go index 1df1243..76e8cdf 100644 --- a/netutil/net_test.go +++ b/netutil/net_test.go @@ -15,14 +15,14 @@ func TestGetInternalIp(t *testing.T) { assert.IsNotNil(ip) } -func TestGetPublicIpInfo(t *testing.T) { - assert := internal.NewAssert(t, "TestGetPublicIpInfo") +// func TestGetPublicIpInfo(t *testing.T) { +// assert := internal.NewAssert(t, "TestGetPublicIpInfo") - publicIpInfo, err := GetPublicIpInfo() - assert.IsNil(err) +// publicIpInfo, err := GetPublicIpInfo() +// assert.IsNil(err) - t.Logf("public ip info is: %+v \n", *publicIpInfo) -} +// t.Logf("public ip info is: %+v \n", *publicIpInfo) +// } func TestIsPublicIP(t *testing.T) { assert := internal.NewAssert(t, "TestIsPublicIP") diff --git a/strutil/string.go b/strutil/string.go index bf80be4..4052925 100644 --- a/strutil/string.go +++ b/strutil/string.go @@ -5,9 +5,11 @@ package strutil import ( + "reflect" "strings" "unicode" "unicode/utf8" + "unsafe" ) // CamelCase covert string to camelCase string. @@ -324,3 +326,80 @@ func WordCount(s string) int { return count } + +// RemoveNonPrintable remove non-printable characters from a string. +func RemoveNonPrintable(str string) string { + result := strings.Map(func(r rune) rune { + if unicode.IsPrint(r) { + return r + } + return -1 + }, str) + + return result +} + +// StringToBytes converts a string to byte slice without a memory allocation. +func StringToBytes(str string) (b []byte) { + sh := *(*reflect.StringHeader)(unsafe.Pointer(&str)) + bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len + return b +} + +// BytesToString converts a byte slice to string without a memory allocation. +// Play: todo +func BytesToString(bytes []byte) string { + return *(*string)(unsafe.Pointer(&bytes)) +} + +// IsBlank checks if a string is whitespace, empty. +func IsBlank(str string) bool { + if len(str) == 0 { + return true + } + // memory copies will occur here, but UTF8 will be compatible + runes := []rune(str) + for _, r := range runes { + if !unicode.IsSpace(r) { + return false + } + } + return true +} + +// HasPrefixAny check if a string starts with any of an array of specified strings. +func HasPrefixAny(str string, prefixes []string) bool { + if len(str) == 0 || len(prefixes) == 0 { + return false + } + for _, prefix := range prefixes { + if strings.HasPrefix(str, prefix) { + return true + } + } + return false +} + +// HasSuffixAny check if a string ends with any of an array of specified strings. +func HasSuffixAny(str string, suffixes []string) bool { + if len(str) == 0 || len(suffixes) == 0 { + return false + } + for _, suffix := range suffixes { + if strings.HasSuffix(str, suffix) { + return true + } + } + return false +} + +// IndexOffset returns the index of the first instance of substr in string after offsetting the string by `idxFrom`, +// or -1 if substr is not present in string. +func IndexOffset(str string, substr string, idxFrom int) int { + if idxFrom > len(str)-1 || idxFrom < 0 { + return -1 + } + + return strings.Index(str[idxFrom:], substr) + idxFrom +} diff --git a/strutil/string_test.go b/strutil/string_test.go index 1799eef..9b79eca 100644 --- a/strutil/string_test.go +++ b/strutil/string_test.go @@ -1,6 +1,7 @@ package strutil import ( + "reflect" "testing" "github.com/duke-git/lancet/internal" @@ -329,3 +330,59 @@ func TestWordCount(t *testing.T) { assert.Equal(v, WordCount(k)) } } + +func TestRemoveNonPrintable(t *testing.T) { + assert := internal.NewAssert(t, "TestRemoveNonPrintable") + + assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n")) + assert.Equal("你好😄", RemoveNonPrintable("你好😄")) +} + +func TestStringToBytes(t *testing.T) { + assert := internal.NewAssert(t, "TestStringToBytes") + str := "abc" + bytes := StringToBytes(str) + assert.Equal(reflect.DeepEqual(bytes, []byte{'a', 'b', 'c'}), true) +} + +func TestBytesToString(t *testing.T) { + assert := internal.NewAssert(t, "TestBytesToString") + bytes := []byte{'a', 'b', 'c'} + str := BytesToString(bytes) + assert.Equal(str == "abc", true) +} + +func TestIsBlank(t *testing.T) { + assert := internal.NewAssert(t, "TestIsBlank") + assert.Equal(IsBlank(""), true) + assert.Equal(IsBlank("\t\v\f\n"), true) + assert.Equal(IsBlank(" 中文"), false) +} + +func TestHasPrefixAny(t *testing.T) { + assert := internal.NewAssert(t, "TestHasPrefixAny") + str := "foo bar" + prefixes := []string{"fo", "xyz", "hello"} + notMatches := []string{"oom", "world"} + assert.Equal(HasPrefixAny(str, prefixes), true) + assert.Equal(HasPrefixAny(str, notMatches), false) +} + +func TestHasSuffixAny(t *testing.T) { + assert := internal.NewAssert(t, "TestHasSuffixAny") + str := "foo bar" + suffixes := []string{"bar", "xyz", "hello"} + notMatches := []string{"oom", "world"} + assert.Equal(HasSuffixAny(str, suffixes), true) + assert.Equal(HasSuffixAny(str, notMatches), false) +} + +func TestIndexOffset(t *testing.T) { + assert := internal.NewAssert(t, "TestIndexOffset") + str := "foo bar hello world" + assert.Equal(IndexOffset(str, "o", 5), 12) + assert.Equal(IndexOffset(str, "o", 0), 1) + assert.Equal(IndexOffset(str, "d", len(str)-1), len(str)-1) + assert.Equal(IndexOffset(str, "d", len(str)), -1) + assert.Equal(IndexOffset(str, "f", -1), -1) +} diff --git a/system/os_darwin.go b/system/os_darwin.go new file mode 100644 index 0000000..dec8a26 --- /dev/null +++ b/system/os_darwin.go @@ -0,0 +1,25 @@ +//go:build darwin + +package system + +import ( + "os/exec" +) + +func WithForeground() Option { + return func(c *exec.Cmd) { + // if c.SysProcAttr == nil { + // c.SysProcAttr = &syscall.SysProcAttr{ + // Foreground: true, + // } + // } else { + // c.SysProcAttr.Foreground = true + // } + } +} + +func WithWinHide() Option { + return func(c *exec.Cmd) { + + } +} diff --git a/system/os_linux.go b/system/os_linux.go new file mode 100644 index 0000000..24c63e6 --- /dev/null +++ b/system/os_linux.go @@ -0,0 +1,26 @@ +//go:build linux + +package system + +import ( + "os/exec" + "syscall" +) + +func WithForeground() Option { + return func(c *exec.Cmd) { + if c.SysProcAttr == nil { + c.SysProcAttr = &syscall.SysProcAttr{ + Foreground: true, + } + } else { + c.SysProcAttr.Foreground = true + } + } +} + +func WithWinHide() Option { + return func(c *exec.Cmd) { + + } +} diff --git a/system/os_windows.go b/system/os_windows.go new file mode 100644 index 0000000..6cd3698 --- /dev/null +++ b/system/os_windows.go @@ -0,0 +1,20 @@ +//go:build windows + +package system + +import ( + "os/exec" + "syscall" +) + +func WithWinHide() Option { + return func(c *exec.Cmd) { + if c.SysProcAttr == nil { + c.SysProcAttr = &syscall.SysProcAttr{ + HideWindow: true, + } + } else { + c.SysProcAttr.HideWindow = true + } + } +}