mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-12 08:42:29 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7e5d946f1 | ||
|
|
687db4ce79 | ||
|
|
a9a4bb8841 | ||
|
|
bc6cb5f61b | ||
|
|
2c57266f8e | ||
|
|
57e49c9520 | ||
|
|
985c9a5d9a | ||
|
|
5cfb11f036 | ||
|
|
5b3d48a1e7 | ||
|
|
d0576e028f | ||
|
|
76bdec2b54 | ||
|
|
fa20aba3a7 | ||
|
|
7a4a429e23 | ||
|
|
a70ec6ad1e | ||
|
|
e435fa271b | ||
|
|
1533d00891 | ||
|
|
8b99641de0 | ||
|
|
251f899f18 | ||
|
|
00407e5182 | ||
|
|
4e457ad672 | ||
|
|
7d8d9c3543 | ||
|
|
1197e8d1b6 | ||
|
|
13bbe19ab2 | ||
|
|
2725575d2f | ||
|
|
037d2729ce | ||
|
|
09d98745b0 | ||
|
|
af5cfe6da1 | ||
|
|
d59259bbe0 | ||
|
|
3189628d54 | ||
|
|
62c5e251a5 | ||
|
|
6e6444c8c0 | ||
|
|
dd613e98b2 | ||
|
|
2d905ab03e |
12
README.md
12
README.md
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js.
|
Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
English | [简体中文](./README_zh-CN.md) | [Website](https://uvdream.github.io/lancet-docs/en/)
|
English | [简体中文](./README_zh-CN.md)
|
||||||
|
|
||||||
## Feature
|
## Feature
|
||||||
|
|
||||||
@@ -38,10 +38,10 @@ English | [简体中文](./README_zh-CN.md) | [Website](https://uvdream.github.i
|
|||||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.3.4. </b>
|
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.3.5. </b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet@v1.3.3 // below go1.18, install latest version of v1.x.x
|
go get github.com/duke-git/lancet@v1.3.5 // below go1.18, install latest version of v1.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -371,7 +371,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#SendRequest)
|
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#SendRequest)
|
||||||
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DecodeResponse)
|
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DecodeResponse)
|
||||||
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues)
|
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues)
|
||||||
|
|
||||||
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
|
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
|
||||||
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
|
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
|
||||||
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
|
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
|
||||||
@@ -488,12 +487,14 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)
|
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)
|
||||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)
|
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)
|
||||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)
|
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)
|
||||||
|
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperKebabCase)
|
||||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)
|
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)
|
||||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
|
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
|
||||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
|
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
|
||||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
|
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
|
||||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Reverse)
|
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Reverse)
|
||||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
|
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
|
||||||
|
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperSnakeCase)
|
||||||
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)
|
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)
|
||||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
|
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
|
||||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
|
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
|
||||||
@@ -551,6 +552,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
|
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
|
||||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
|
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
|
||||||
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsZeroValue)
|
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsZeroValue)
|
||||||
|
- [IsGBK](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsGBK)
|
||||||
|
|
||||||
### 20. xerror package implements helpers for errors.
|
### 20. xerror package implements helpers for errors.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
lancet(柳叶刀)是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。
|
lancet(柳叶刀)是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
简体中文 | [English](./README.md) | [文档](https://uvdream.github.io/lancet-docs)
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
@@ -37,10 +37,10 @@
|
|||||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.4。</b>
|
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.5。</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet@v1.3.3 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
go get github.com/duke-git/lancet@v1.3.5 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||||
```
|
```
|
||||||
|
|
||||||
## 用法
|
## 用法
|
||||||
@@ -370,7 +370,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest)
|
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest)
|
||||||
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse)
|
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse)
|
||||||
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues)
|
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues)
|
||||||
|
|
||||||
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
|
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
|
||||||
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
|
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
|
||||||
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
|
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
|
||||||
@@ -485,12 +484,14 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)
|
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)
|
||||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)
|
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)
|
||||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)
|
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)
|
||||||
|
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperKebabCase)
|
||||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)
|
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)
|
||||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
|
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
|
||||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
|
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
|
||||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
|
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
|
||||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Reverse)
|
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Reverse)
|
||||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
|
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
|
||||||
|
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperSnakeCase)
|
||||||
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)
|
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)
|
||||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
||||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
||||||
@@ -548,6 +549,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
|
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
|
||||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
|
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
|
||||||
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)
|
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)
|
||||||
|
- [IsGBK](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)
|
||||||
|
|
||||||
### 20. xerror 包实现一些错误处理函数
|
### 20. xerror 包实现一些错误处理函数
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-ch
|
|||||||
var stream <-chan any
|
var stream <-chan any
|
||||||
select {
|
select {
|
||||||
case maybeStream, ok := <-chanStream:
|
case maybeStream, ok := <-chanStream:
|
||||||
if ok == false {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stream = maybeStream
|
stream = maybeStream
|
||||||
|
|||||||
@@ -97,40 +97,43 @@ func ToString(value any) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch value.(type) {
|
switch val := value.(type) {
|
||||||
case float32:
|
case float32:
|
||||||
return strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32)
|
return strconv.FormatFloat(float64(val), 'f', -1, 32)
|
||||||
case float64:
|
case float64:
|
||||||
return strconv.FormatFloat(value.(float64), 'f', -1, 64)
|
return strconv.FormatFloat(val, 'f', -1, 64)
|
||||||
case int:
|
case int:
|
||||||
return strconv.FormatInt(int64(value.(int)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int8:
|
case int8:
|
||||||
return strconv.FormatInt(int64(value.(int8)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int16:
|
case int16:
|
||||||
return strconv.FormatInt(int64(value.(int16)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int32:
|
case int32:
|
||||||
return strconv.FormatInt(int64(value.(int32)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int64:
|
case int64:
|
||||||
return strconv.FormatInt(value.(int64), 10)
|
return strconv.FormatInt(val, 10)
|
||||||
case uint:
|
case uint:
|
||||||
return strconv.FormatUint(uint64(value.(uint)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint8:
|
case uint8:
|
||||||
return strconv.FormatUint(uint64(value.(uint8)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint16:
|
case uint16:
|
||||||
return strconv.FormatUint(uint64(value.(uint16)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint32:
|
case uint32:
|
||||||
return strconv.FormatUint(uint64(value.(uint32)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint64:
|
case uint64:
|
||||||
return strconv.FormatUint(value.(uint64), 10)
|
return strconv.FormatUint(val, 10)
|
||||||
case string:
|
case string:
|
||||||
return value.(string)
|
return val
|
||||||
case []byte:
|
case []byte:
|
||||||
return string(value.([]byte))
|
return string(val)
|
||||||
default:
|
default:
|
||||||
newValue, _ := json.Marshal(value)
|
b, err := json.Marshal(val)
|
||||||
return string(newValue)
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
|
||||||
// todo: maybe we should't supprt other type convertion
|
// todo: maybe we should't supprt other type conversion
|
||||||
// v := reflect.ValueOf(value)
|
// v := reflect.ValueOf(value)
|
||||||
// log.Panicf("Unsupported data type: %s ", v.String())
|
// log.Panicf("Unsupported data type: %s ", v.String())
|
||||||
// return ""
|
// return ""
|
||||||
|
|||||||
@@ -27,14 +27,9 @@ func TestToChannel(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestToChannel")
|
assert := internal.NewAssert(t, "TestToChannel")
|
||||||
|
|
||||||
ch := ToChannel([]int{1, 2, 3})
|
ch := ToChannel([]int{1, 2, 3})
|
||||||
val1, _ := <-ch
|
assert.Equal(1, <-ch)
|
||||||
assert.Equal(1, val1)
|
assert.Equal(2, <-ch)
|
||||||
|
assert.Equal(3, <-ch)
|
||||||
val2, _ := <-ch
|
|
||||||
assert.Equal(2, val2)
|
|
||||||
|
|
||||||
val3, _ := <-ch
|
|
||||||
assert.Equal(3, val3)
|
|
||||||
|
|
||||||
_, ok := <-ch
|
_, ok := <-ch
|
||||||
assert.Equal(false, ok)
|
assert.Equal(false, ok)
|
||||||
@@ -254,6 +249,7 @@ func TestDecodeByte(t *testing.T) {
|
|||||||
|
|
||||||
var obj string
|
var obj string
|
||||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
DecodeByte(byteData, &obj)
|
err := DecodeByte(byteData, &obj)
|
||||||
|
assert.IsNil(err)
|
||||||
assert.Equal("abc", obj)
|
assert.Equal("abc", obj)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,19 @@ import (
|
|||||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||||
// len(key) should be 16, 24 or 32
|
// len(key) should be 16, 24 or 32
|
||||||
func AesEcbEncrypt(data, key []byte) []byte {
|
func AesEcbEncrypt(data, key []byte) []byte {
|
||||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
|
||||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||||
plain := make([]byte, length*aes.BlockSize)
|
plain := make([]byte, length*aes.BlockSize)
|
||||||
|
|
||||||
copy(plain, data)
|
copy(plain, data)
|
||||||
|
|
||||||
pad := byte(len(plain) - len(data))
|
pad := byte(len(plain) - len(data))
|
||||||
for i := len(data); i < len(plain); i++ {
|
for i := len(data); i < len(plain); i++ {
|
||||||
plain[i] = pad
|
plain[i] = pad
|
||||||
}
|
}
|
||||||
|
|
||||||
encrypted := make([]byte, len(plain))
|
encrypted := make([]byte, len(plain))
|
||||||
|
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||||
|
|
||||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||||
}
|
}
|
||||||
@@ -108,27 +112,32 @@ func AesCfbEncrypt(data, key []byte) []byte {
|
|||||||
|
|
||||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||||
iv := encrypted[:aes.BlockSize]
|
iv := encrypted[:aes.BlockSize]
|
||||||
|
|
||||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stream := cipher.NewCFBEncrypter(block, iv)
|
stream := cipher.NewCFBEncrypter(block, iv)
|
||||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||||
|
|
||||||
return encrypted
|
return encrypted
|
||||||
}
|
}
|
||||||
|
|
||||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
||||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
if len(encrypted) < aes.BlockSize {
|
if len(encrypted) < aes.BlockSize {
|
||||||
panic("encrypted data is too short")
|
panic("encrypted data is too short")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
iv := encrypted[:aes.BlockSize]
|
iv := encrypted[:aes.BlockSize]
|
||||||
encrypted = encrypted[aes.BlockSize:]
|
encrypted = encrypted[aes.BlockSize:]
|
||||||
|
|
||||||
stream := cipher.NewCFBDecrypter(block, iv)
|
stream := cipher.NewCFBDecrypter(block, iv)
|
||||||
|
|
||||||
stream.XORKeyStream(encrypted, encrypted)
|
stream.XORKeyStream(encrypted, encrypted)
|
||||||
|
|
||||||
return encrypted
|
return encrypted
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +148,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data = pkcs7Padding(data, aes.BlockSize)
|
data = pkcs7Padding(data, aes.BlockSize)
|
||||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||||
iv := encrypted[:aes.BlockSize]
|
iv := encrypted[:aes.BlockSize]
|
||||||
@@ -148,6 +158,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
|
|||||||
|
|
||||||
stream := cipher.NewOFB(block, iv)
|
stream := cipher.NewOFB(block, iv)
|
||||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||||
|
|
||||||
return encrypted
|
return encrypted
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,5 +181,6 @@ func AesOfbDecrypt(data, key []byte) []byte {
|
|||||||
mode.XORKeyStream(decrypted, data)
|
mode.XORKeyStream(decrypted, data)
|
||||||
|
|
||||||
decrypted = pkcs7UnPadding(decrypted)
|
decrypted = pkcs7UnPadding(decrypted)
|
||||||
|
|
||||||
return decrypted
|
return decrypted
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||||
// len(key) should be 8
|
// len(key) should be 8
|
||||||
func DesEcbEncrypt(data, key []byte) []byte {
|
func DesEcbEncrypt(data, key []byte) []byte {
|
||||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
|
||||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||||
plain := make([]byte, length*des.BlockSize)
|
plain := make([]byte, length*des.BlockSize)
|
||||||
copy(plain, data)
|
copy(plain, data)
|
||||||
@@ -26,6 +25,8 @@ func DesEcbEncrypt(data, key []byte) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
encrypted := make([]byte, len(plain))
|
encrypted := make([]byte, len(plain))
|
||||||
|
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||||
|
|
||||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||||
}
|
}
|
||||||
@@ -59,6 +60,7 @@ func DesCbcEncrypt(data, key []byte) []byte {
|
|||||||
|
|
||||||
encrypted := make([]byte, des.BlockSize+len(data))
|
encrypted := make([]byte, des.BlockSize+len(data))
|
||||||
iv := encrypted[:des.BlockSize]
|
iv := encrypted[:des.BlockSize]
|
||||||
|
|
||||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,11 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
pem.Encode(file, &block)
|
err = pem.Encode(file, &block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
file.Close()
|
file.Close()
|
||||||
|
|
||||||
// public key
|
// public key
|
||||||
@@ -49,12 +53,16 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
|||||||
Bytes: derpText,
|
Bytes: derpText,
|
||||||
}
|
}
|
||||||
|
|
||||||
//file,err = os.Create("rsa_public.pem")
|
|
||||||
file, err = os.Create(pubKeyFile)
|
file, err = os.Create(pubKeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pem.Encode(file, &block)
|
|
||||||
|
err = pem.Encode(file, &block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
file.Close()
|
file.Close()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -72,7 +80,11 @@ func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
buf := make([]byte, fileInfo.Size())
|
buf := make([]byte, fileInfo.Size())
|
||||||
file.Read(buf)
|
|
||||||
|
_, err = file.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
block, _ := pem.Decode(buf)
|
block, _ := pem.Decode(buf)
|
||||||
|
|
||||||
@@ -101,7 +113,11 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
|||||||
}
|
}
|
||||||
buf := make([]byte, fileInfo.Size())
|
buf := make([]byte, fileInfo.Size())
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
file.Read(buf)
|
|
||||||
|
_, err = file.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
block, _ := pem.Decode(buf)
|
block, _ := pem.Decode(buf)
|
||||||
|
|
||||||
|
|||||||
@@ -146,9 +146,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
|||||||
lastNum := powerTwo(level - 1)
|
lastNum := powerTwo(level - 1)
|
||||||
lastLen := lastNum + (lastNum - 1)
|
lastLen := lastNum + (lastNum - 1)
|
||||||
|
|
||||||
heapTree := make([][]string, level, level)
|
heapTree := make([][]string, level)
|
||||||
for i := 0; i < level; i++ {
|
for i := 0; i < level; i++ {
|
||||||
heapTree[i] = make([]string, lastLen, lastLen)
|
heapTree[i] = make([]string, lastLen)
|
||||||
for j := 0; j < lastLen; j++ {
|
for j := 0; j < lastLen; j++ {
|
||||||
heapTree[i][j] = ""
|
heapTree[i][j] = ""
|
||||||
}
|
}
|
||||||
@@ -169,9 +169,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
|||||||
for n := 0; n < lastLen; n++ {
|
for n := 0; n < lastLen; n++ {
|
||||||
val := heapTree[m][n]
|
val := heapTree[m][n]
|
||||||
if val == "" {
|
if val == "" {
|
||||||
fmt.Printf(" ")
|
fmt.Print(" ")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(val)
|
fmt.Print(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ func TestMaxHeap_BuildMaxHeap(t *testing.T) {
|
|||||||
assert.Equal(expected, heap.data)
|
assert.Equal(expected, heap.data)
|
||||||
|
|
||||||
assert.Equal(12, heap.Size())
|
assert.Equal(12, heap.Size())
|
||||||
|
|
||||||
heap.PrintStructure()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaxHeap_Push(t *testing.T) {
|
func TestMaxHeap_Push(t *testing.T) {
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package datastructure
|
package datastructure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/datastructure"
|
"github.com/duke-git/lancet/v2/datastructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the link, Next pointer points to a next node of the link.
|
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the dl, Next pointer points to a next node of the dl.
|
||||||
type DoublyLink[T any] struct {
|
type DoublyLink[T any] struct {
|
||||||
Head *datastructure.LinkNode[T]
|
Head *datastructure.LinkNode[T]
|
||||||
length int
|
length int
|
||||||
@@ -19,30 +18,30 @@ func NewDoublyLink[T any]() *DoublyLink[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtHead insert value into doubly linklist at head index
|
// InsertAtHead insert value into doubly linklist at head index
|
||||||
func (link *DoublyLink[T]) InsertAtHead(value T) {
|
func (dl *DoublyLink[T]) InsertAtHead(value T) {
|
||||||
newNode := datastructure.NewLinkNode(value)
|
newNode := datastructure.NewLinkNode(value)
|
||||||
size := link.Size()
|
size := dl.Size()
|
||||||
|
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
link.Head = newNode
|
dl.Head = newNode
|
||||||
link.length++
|
dl.length++
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newNode.Next = link.Head
|
newNode.Next = dl.Head
|
||||||
newNode.Pre = nil
|
newNode.Pre = nil
|
||||||
|
|
||||||
link.Head.Pre = newNode
|
dl.Head.Pre = newNode
|
||||||
link.Head = newNode
|
dl.Head = newNode
|
||||||
|
|
||||||
link.length++
|
dl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtTail insert value into doubly linklist at tail index
|
// InsertAtTail insert value into doubly linklist at tail index
|
||||||
func (link *DoublyLink[T]) InsertAtTail(value T) {
|
func (dl *DoublyLink[T]) InsertAtTail(value T) {
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
if current == nil {
|
if current == nil {
|
||||||
link.InsertAtHead(value)
|
dl.InsertAtHead(value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,28 +54,29 @@ func (link *DoublyLink[T]) InsertAtTail(value T) {
|
|||||||
newNode.Pre = current
|
newNode.Pre = current
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
|
|
||||||
link.length++
|
dl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAt insert value into doubly linklist at index
|
// InsertAt insert value into doubly linklist at index
|
||||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
// param `index` should between [0, length], if index do not meet the conditions, do nothing
|
||||||
size := link.length
|
func (dl *DoublyLink[T]) InsertAt(index int, value T) {
|
||||||
|
size := dl.length
|
||||||
if index < 0 || index > size {
|
if index < 0 || index > size {
|
||||||
return errors.New("param index should between 0 and the length of doubly link.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
link.InsertAtHead(value)
|
dl.InsertAtHead(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == size {
|
if index == size {
|
||||||
link.InsertAtTail(value)
|
dl.InsertAtTail(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
@@ -85,38 +85,36 @@ func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
|||||||
newNode.Pre = current
|
newNode.Pre = current
|
||||||
|
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
link.length++
|
dl.length++
|
||||||
|
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("doubly link list no exist")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtHead delete value in doubly linklist at head index
|
// DeleteAtHead delete value in doubly linklist at head index
|
||||||
func (link *DoublyLink[T]) DeleteAtHead() error {
|
func (dl *DoublyLink[T]) DeleteAtHead() {
|
||||||
if link.Head == nil {
|
if dl.Head == nil {
|
||||||
return errors.New("doubly link list no exist")
|
return
|
||||||
}
|
|
||||||
current := link.Head
|
|
||||||
link.Head = current.Next
|
|
||||||
link.Head.Pre = nil
|
|
||||||
link.length--
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtTail delete value in doubly linklist at tail index
|
current := dl.Head
|
||||||
func (link *DoublyLink[T]) DeleteAtTail() error {
|
dl.Head = current.Next
|
||||||
if link.Head == nil {
|
dl.Head.Pre = nil
|
||||||
return errors.New("doubly link list no exist")
|
dl.length--
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
// DeleteAtTail delete value in doubly linklist at tail
|
||||||
|
func (dl *DoublyLink[T]) DeleteAtTail() {
|
||||||
|
if dl.Head == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
current := dl.Head
|
||||||
if current.Next == nil {
|
if current.Next == nil {
|
||||||
return link.DeleteAtHead()
|
dl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
for current.Next.Next != nil {
|
for current.Next.Next != nil {
|
||||||
@@ -124,45 +122,44 @@ func (link *DoublyLink[T]) DeleteAtTail() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
current.Next = nil
|
current.Next = nil
|
||||||
link.length--
|
dl.length--
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAt delete value in doubly linklist at index
|
// DeleteAt delete value in doubly linklist at index
|
||||||
func (link *DoublyLink[T]) DeleteAt(index int) error {
|
// param `index` should be [0, len(DoublyLink)-1]
|
||||||
if link.Head == nil {
|
func (dl *DoublyLink[T]) DeleteAt(index int) {
|
||||||
return errors.New("doubly link list no exist")
|
if dl.Head == nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
current := dl.Head
|
||||||
if current.Next == nil || index == 0 {
|
if current.Next == nil || index == 0 {
|
||||||
return link.DeleteAtHead()
|
dl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == link.length-1 {
|
if index == dl.length-1 {
|
||||||
return link.DeleteAtTail()
|
dl.DeleteAtTail()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index < 0 || index > link.length-1 {
|
if index < 0 || index > dl.length-1 {
|
||||||
return errors.New("param index should between 0 and link size -1.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
current.Next = current.Next.Next
|
current.Next = current.Next.Next
|
||||||
link.length--
|
dl.length--
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("delete error")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse the linked list
|
// Reverse the linked list
|
||||||
func (link *DoublyLink[T]) Reverse() {
|
func (dl *DoublyLink[T]) Reverse() {
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
var temp *datastructure.LinkNode[T]
|
var temp *datastructure.LinkNode[T]
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
@@ -173,20 +170,20 @@ func (link *DoublyLink[T]) Reverse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if temp != nil {
|
if temp != nil {
|
||||||
link.Head = temp.Pre
|
dl.Head = temp.Pre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMiddleNode return node at middle index of linked list
|
// GetMiddleNode return node at middle index of linked list
|
||||||
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
func (dl *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||||
if link.Head == nil {
|
if dl.Head == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if link.Head.Next == nil {
|
if dl.Head.Next == nil {
|
||||||
return link.Head
|
return dl.Head
|
||||||
}
|
}
|
||||||
fast := link.Head
|
fast := dl.Head
|
||||||
slow := link.Head
|
slow := dl.Head
|
||||||
|
|
||||||
for fast != nil {
|
for fast != nil {
|
||||||
fast = fast.Next
|
fast = fast.Next
|
||||||
@@ -202,14 +199,14 @@ func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size return the count of doubly linked list
|
// Size return the count of doubly linked list
|
||||||
func (link *DoublyLink[T]) Size() int {
|
func (dl *DoublyLink[T]) Size() int {
|
||||||
return link.length
|
return dl.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values return slice of all doubly linklist node value
|
// Values return slice of all doubly linklist node value
|
||||||
func (link *DoublyLink[T]) Values() []T {
|
func (dl *DoublyLink[T]) Values() []T {
|
||||||
result := []T{}
|
result := []T{}
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
for current != nil {
|
for current != nil {
|
||||||
result = append(result, current.Value)
|
result = append(result, current.Value)
|
||||||
current = current.Next
|
current = current.Next
|
||||||
@@ -218,8 +215,8 @@ func (link *DoublyLink[T]) Values() []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print all nodes info of a linked list
|
// Print all nodes info of a linked list
|
||||||
func (link *DoublyLink[T]) Print() {
|
func (dl *DoublyLink[T]) Print() {
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
info := "[ "
|
info := "[ "
|
||||||
for current != nil {
|
for current != nil {
|
||||||
info += fmt.Sprintf("%+v, ", current)
|
info += fmt.Sprintf("%+v, ", current)
|
||||||
@@ -229,13 +226,13 @@ func (link *DoublyLink[T]) Print() {
|
|||||||
fmt.Println(info)
|
fmt.Println(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty checks if link is empty or not
|
// IsEmpty checks if dl is empty or not
|
||||||
func (link *DoublyLink[T]) IsEmpty() bool {
|
func (dl *DoublyLink[T]) IsEmpty() bool {
|
||||||
return link.length == 0
|
return dl.length == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all nodes in doubly linklist
|
// Clear all nodes in doubly linklist
|
||||||
func (link *DoublyLink[T]) Clear() {
|
func (dl *DoublyLink[T]) Clear() {
|
||||||
link.Head = nil
|
dl.Head = nil
|
||||||
link.length = 0
|
dl.length = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,29 +41,24 @@ func TestDoublyLink_InsertAt(t *testing.T) {
|
|||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
|
|
||||||
err := link.InsertAt(1, 1)
|
link.InsertAt(1, 1) //do nothing
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAt(0, 1)
|
link.InsertAt(0, 1)
|
||||||
link.InsertAt(1, 2)
|
link.InsertAt(1, 2)
|
||||||
link.InsertAt(2, 4)
|
link.InsertAt(2, 4)
|
||||||
link.InsertAt(2, 3)
|
link.InsertAt(2, 3)
|
||||||
|
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{1, 2, 3, 4}
|
expected := []int{1, 2, 3, 4}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
|
|
||||||
assert.Equal(expected, values)
|
assert.Equal(expected, values)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
|
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
|
||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
err := link.DeleteAtHead()
|
link.DeleteAtHead()
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -71,7 +66,6 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.DeleteAtHead()
|
link.DeleteAtHead()
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{2, 3, 4}
|
expected := []int{2, 3, 4}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
@@ -83,8 +77,7 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
|
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
|
||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
err := link.DeleteAtTail()
|
link.DeleteAtTail()
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -92,7 +85,6 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.DeleteAtTail()
|
link.DeleteAtTail()
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{1, 2, 3}
|
expected := []int{1, 2, 3}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
@@ -104,8 +96,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
|
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
|
||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
err := link.DeleteAt(0)
|
link.DeleteAt(0)
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -113,11 +104,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
link.InsertAtTail(5)
|
link.InsertAtTail(5)
|
||||||
|
|
||||||
err = link.DeleteAt(5)
|
link.DeleteAt(0)
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
err = link.DeleteAt(0)
|
|
||||||
assert.IsNil(err)
|
|
||||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||||
|
|
||||||
link.DeleteAt(3)
|
link.DeleteAt(3)
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package datastructure
|
package datastructure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/datastructure"
|
"github.com/duke-git/lancet/v2/datastructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the link.
|
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the sl.
|
||||||
type SinglyLink[T any] struct {
|
type SinglyLink[T any] struct {
|
||||||
Head *datastructure.LinkNode[T]
|
Head *datastructure.LinkNode[T]
|
||||||
length int
|
length int
|
||||||
@@ -20,18 +19,18 @@ func NewSinglyLink[T any]() *SinglyLink[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtHead insert value into singly linklist at head index
|
// InsertAtHead insert value into singly linklist at head index
|
||||||
func (link *SinglyLink[T]) InsertAtHead(value T) {
|
func (sl *SinglyLink[T]) InsertAtHead(value T) {
|
||||||
newNode := datastructure.NewLinkNode(value)
|
newNode := datastructure.NewLinkNode(value)
|
||||||
newNode.Next = link.Head
|
newNode.Next = sl.Head
|
||||||
link.Head = newNode
|
sl.Head = newNode
|
||||||
link.length++
|
sl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtTail insert value into singly linklist at tail index
|
// InsertAtTail insert value into singly linklist at tail index
|
||||||
func (link *SinglyLink[T]) InsertAtTail(value T) {
|
func (sl *SinglyLink[T]) InsertAtTail(value T) {
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
if current == nil {
|
if current == nil {
|
||||||
link.InsertAtHead(value)
|
sl.InsertAtHead(value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,65 +42,63 @@ func (link *SinglyLink[T]) InsertAtTail(value T) {
|
|||||||
newNode.Next = nil
|
newNode.Next = nil
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
|
|
||||||
link.length++
|
sl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAt insert value into singly linklist at index
|
// InsertAt insert value into singly linklist at index
|
||||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
|
// param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing
|
||||||
size := link.length
|
func (sl *SinglyLink[T]) InsertAt(index int, value T) {
|
||||||
|
size := sl.length
|
||||||
if index < 0 || index > size {
|
if index < 0 || index > size {
|
||||||
return errors.New("param index should between 0 and the length of singly link.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
link.InsertAtHead(value)
|
sl.InsertAtHead(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == size {
|
if index == size {
|
||||||
link.InsertAtTail(value)
|
sl.InsertAtTail(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
newNode := datastructure.NewLinkNode(value)
|
newNode := datastructure.NewLinkNode(value)
|
||||||
newNode.Next = current.Next
|
newNode.Next = current.Next
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
link.length++
|
sl.length++
|
||||||
|
return
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("singly link list no exist")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtHead delete value in singly linklist at head index
|
// DeleteAtHead delete value in singly linklist at head index
|
||||||
func (link *SinglyLink[T]) DeleteAtHead() error {
|
func (sl *SinglyLink[T]) DeleteAtHead() {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return errors.New("singly link list no exist")
|
return
|
||||||
}
|
|
||||||
current := link.Head
|
|
||||||
link.Head = current.Next
|
|
||||||
link.length--
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtTail delete value in singly linklist at tail index
|
current := sl.Head
|
||||||
func (link *SinglyLink[T]) DeleteAtTail() error {
|
sl.Head = current.Next
|
||||||
if link.Head == nil {
|
sl.length--
|
||||||
return errors.New("singly link list no exist")
|
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
// DeleteAtTail delete value in singly linklist at tail
|
||||||
|
func (sl *SinglyLink[T]) DeleteAtTail() {
|
||||||
|
if sl.Head == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
current := sl.Head
|
||||||
if current.Next == nil {
|
if current.Next == nil {
|
||||||
return link.DeleteAtHead()
|
sl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
for current.Next.Next != nil {
|
for current.Next.Next != nil {
|
||||||
@@ -109,68 +106,66 @@ func (link *SinglyLink[T]) DeleteAtTail() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
current.Next = nil
|
current.Next = nil
|
||||||
link.length--
|
sl.length--
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAt delete value in singly linklist at index
|
// DeleteAt delete value in singly linklist at index
|
||||||
func (link *SinglyLink[T]) DeleteAt(index int) error {
|
// param `index` should be [0, len(SinglyLink)-1]
|
||||||
if link.Head == nil {
|
func (sl *SinglyLink[T]) DeleteAt(index int) {
|
||||||
return errors.New("singly link list no exist")
|
if sl.Head == nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
if current.Next == nil || index == 0 {
|
if current.Next == nil || index == 0 {
|
||||||
return link.DeleteAtHead()
|
sl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == link.length-1 {
|
if index == sl.length-1 {
|
||||||
return link.DeleteAtTail()
|
sl.DeleteAtTail()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index < 0 || index > link.length-1 {
|
if index < 0 || index > sl.length-1 {
|
||||||
return errors.New("param index should between 0 and link size -1.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
current.Next = current.Next.Next
|
current.Next = current.Next.Next
|
||||||
link.length--
|
sl.length--
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("delete error")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteValue delete value in singly linklist
|
// DeleteValue delete value in singly linklist
|
||||||
func (link *SinglyLink[T]) DeleteValue(value T) {
|
func (sl *SinglyLink[T]) DeleteValue(value T) {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dummyHead := datastructure.NewLinkNode(value)
|
dummyHead := datastructure.NewLinkNode(value)
|
||||||
dummyHead.Next = link.Head
|
dummyHead.Next = sl.Head
|
||||||
current := dummyHead
|
current := dummyHead
|
||||||
|
|
||||||
for current.Next != nil {
|
for current.Next != nil {
|
||||||
if reflect.DeepEqual(current.Next.Value, value) {
|
if reflect.DeepEqual(current.Next.Value, value) {
|
||||||
current.Next = current.Next.Next
|
current.Next = current.Next.Next
|
||||||
link.length--
|
sl.length--
|
||||||
} else {
|
} else {
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
link.Head = dummyHead.Next
|
sl.Head = dummyHead.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse the linked list
|
// Reverse the linked list
|
||||||
func (link *SinglyLink[T]) Reverse() {
|
func (sl *SinglyLink[T]) Reverse() {
|
||||||
var pre, next *datastructure.LinkNode[T]
|
var pre, next *datastructure.LinkNode[T]
|
||||||
|
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
next = current.Next
|
next = current.Next
|
||||||
@@ -179,19 +174,19 @@ func (link *SinglyLink[T]) Reverse() {
|
|||||||
current = next
|
current = next
|
||||||
}
|
}
|
||||||
|
|
||||||
link.Head = pre
|
sl.Head = pre
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMiddleNode return node at middle index of linked list
|
// GetMiddleNode return node at middle index of linked list
|
||||||
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
func (sl *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if link.Head.Next == nil {
|
if sl.Head.Next == nil {
|
||||||
return link.Head
|
return sl.Head
|
||||||
}
|
}
|
||||||
fast := link.Head
|
fast := sl.Head
|
||||||
slow := link.Head
|
slow := sl.Head
|
||||||
|
|
||||||
for fast != nil {
|
for fast != nil {
|
||||||
fast = fast.Next
|
fast = fast.Next
|
||||||
@@ -207,14 +202,14 @@ func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size return the count of singly linked list
|
// Size return the count of singly linked list
|
||||||
func (link *SinglyLink[T]) Size() int {
|
func (sl *SinglyLink[T]) Size() int {
|
||||||
return link.length
|
return sl.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values return slice of all singly linklist node value
|
// Values return slice of all singly linklist node value
|
||||||
func (link *SinglyLink[T]) Values() []T {
|
func (sl *SinglyLink[T]) Values() []T {
|
||||||
result := []T{}
|
result := []T{}
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
for current != nil {
|
for current != nil {
|
||||||
result = append(result, current.Value)
|
result = append(result, current.Value)
|
||||||
current = current.Next
|
current = current.Next
|
||||||
@@ -222,20 +217,20 @@ func (link *SinglyLink[T]) Values() []T {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty checks if link is empty or not
|
// IsEmpty checks if sl is empty or not
|
||||||
func (link *SinglyLink[T]) IsEmpty() bool {
|
func (sl *SinglyLink[T]) IsEmpty() bool {
|
||||||
return link.length == 0
|
return sl.length == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all the node in singly linklist
|
// Clear all the node in singly linklist
|
||||||
func (link *SinglyLink[T]) Clear() {
|
func (sl *SinglyLink[T]) Clear() {
|
||||||
link.Head = nil
|
sl.Head = nil
|
||||||
link.length = 0
|
sl.length = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print all nodes info of a linked list
|
// Print all nodes info of a linked list
|
||||||
func (link *SinglyLink[T]) Print() {
|
func (sl *SinglyLink[T]) Print() {
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
info := "[ "
|
info := "[ "
|
||||||
for current != nil {
|
for current != nil {
|
||||||
info += fmt.Sprintf("%+v, ", current)
|
info += fmt.Sprintf("%+v, ", current)
|
||||||
|
|||||||
@@ -41,25 +41,12 @@ func TestSinglyLink_InsertAt(t *testing.T) {
|
|||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
|
|
||||||
err := link.InsertAt(1, 1)
|
link.InsertAt(1, 1) //do nothing
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
err = link.InsertAt(0, 1)
|
link.InsertAt(0, 1)
|
||||||
if err != nil {
|
link.InsertAt(1, 2)
|
||||||
t.FailNow()
|
link.InsertAt(2, 4)
|
||||||
}
|
link.InsertAt(2, 3)
|
||||||
err = link.InsertAt(1, 2)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
err = link.InsertAt(2, 4)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
err = link.InsertAt(2, 3)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
link.Print()
|
link.Print()
|
||||||
|
|
||||||
@@ -73,8 +60,8 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
|
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
|
||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
err := link.DeleteAtHead()
|
|
||||||
assert.IsNotNil(err)
|
link.DeleteAtHead()
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -94,8 +81,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
|
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
|
||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
err := link.DeleteAtTail()
|
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -103,7 +88,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.DeleteAtTail()
|
link.DeleteAtTail()
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{1, 2, 3}
|
expected := []int{1, 2, 3}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
@@ -133,8 +117,6 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
|
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
|
||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
err := link.DeleteAt(0)
|
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -142,11 +124,7 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
link.InsertAtTail(5)
|
link.InsertAtTail(5)
|
||||||
|
|
||||||
err = link.DeleteAt(5)
|
link.DeleteAt(0)
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
err = link.DeleteAt(0)
|
|
||||||
assert.IsNil(err)
|
|
||||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||||
|
|
||||||
link.DeleteAt(3)
|
link.DeleteAt(3)
|
||||||
@@ -167,7 +145,6 @@ func TestSinglyLink_Reverse(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.Reverse()
|
link.Reverse()
|
||||||
link.Print()
|
|
||||||
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ func (l *List[T]) DeleteAt(index int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if index == size-1 {
|
if index == size-1 {
|
||||||
data = append(data[:index])
|
data = data[:index]
|
||||||
} else {
|
} else {
|
||||||
data = append(data[:index], data[index+1:]...)
|
data = append(data[:index], data[index+1:]...)
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ func (l *List[T]) DeleteIf(f func(T) bool) int {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if index == size-1 {
|
if index == size-1 {
|
||||||
data = append(data[:index])
|
data = data[:index]
|
||||||
} else {
|
} else {
|
||||||
data = append(data[:index], data[index+1:]...)
|
data = append(data[:index], data[index+1:]...)
|
||||||
index--
|
index--
|
||||||
@@ -221,7 +221,7 @@ func (l *List[T]) IsEmpty() bool {
|
|||||||
|
|
||||||
// Clear the data of list
|
// Clear the data of list
|
||||||
func (l *List[T]) Clear() {
|
func (l *List[T]) Clear() {
|
||||||
l.data = make([]T, 0, 0)
|
l.data = make([]T, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone return a copy of list
|
// Clone return a copy of list
|
||||||
@@ -235,7 +235,7 @@ func (l *List[T]) Clone() *List[T] {
|
|||||||
// Merge two list, return new list, don't change original list
|
// Merge two list, return new list, don't change original list
|
||||||
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||||
l1, l2 := len(l.data), len(other.data)
|
l1, l2 := len(l.data), len(other.data)
|
||||||
ml := NewList(make([]T, l1+l2, l1+l2))
|
ml := NewList(make([]T, l1+l2))
|
||||||
|
|
||||||
data := append([]T{}, append(l.data, other.data...)...)
|
data := append([]T{}, append(l.data, other.data...)...)
|
||||||
ml.data = data
|
ml.data = data
|
||||||
@@ -274,7 +274,7 @@ func (l *List[T]) Unique() {
|
|||||||
data := l.data
|
data := l.data
|
||||||
size := len(data)
|
size := len(data)
|
||||||
|
|
||||||
uniqueData := make([]T, 0, 0)
|
uniqueData := make([]T, 0)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
value := data[i]
|
value := data[i]
|
||||||
skip := true
|
skip := true
|
||||||
@@ -305,7 +305,7 @@ func (l *List[T]) Union(other *List[T]) *List[T] {
|
|||||||
|
|
||||||
// Intersection creates a new list whose element both be contained in list l and other
|
// Intersection creates a new list whose element both be contained in list l and other
|
||||||
func (l *List[T]) Intersection(other *List[T]) *List[T] {
|
func (l *List[T]) Intersection(other *List[T]) *List[T] {
|
||||||
result := NewList(make([]T, 0, 0))
|
result := NewList(make([]T, 0))
|
||||||
|
|
||||||
for _, v := range l.data {
|
for _, v := range l.data {
|
||||||
if other.Contain(v) {
|
if other.Contain(v) {
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ func TestArrayQueue_Enqueue(t *testing.T) {
|
|||||||
data := queue.Data()
|
data := queue.Data()
|
||||||
size := queue.Size()
|
size := queue.Size()
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal(expected, data)
|
assert.Equal(expected, data)
|
||||||
assert.Equal(3, size)
|
assert.Equal(3, size)
|
||||||
}
|
}
|
||||||
@@ -35,7 +33,6 @@ func TestArrayQueue_Dequeue(t *testing.T) {
|
|||||||
val, ok := queue.Dequeue()
|
val, ok := queue.Dequeue()
|
||||||
assert.Equal(true, ok)
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
assert.Equal(1, val)
|
assert.Equal(1, val)
|
||||||
assert.Equal([]int{2, 3}, queue.Data())
|
assert.Equal([]int{2, 3}, queue.Data())
|
||||||
}
|
}
|
||||||
@@ -50,8 +47,6 @@ func TestArrayQueue_Front(t *testing.T) {
|
|||||||
|
|
||||||
val := queue.Front()
|
val := queue.Front()
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal(1, val)
|
assert.Equal(1, val)
|
||||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||||
}
|
}
|
||||||
@@ -66,8 +61,6 @@ func TestArrayQueue_Back(t *testing.T) {
|
|||||||
|
|
||||||
val := queue.Back()
|
val := queue.Back()
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal(3, val)
|
assert.Equal(3, val)
|
||||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,31 +10,43 @@ func TestCircularQueue_Enqueue(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
|
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](6)
|
||||||
queue.Enqueue(1)
|
|
||||||
queue.Enqueue(2)
|
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(2)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(4)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(5)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||||
assert.Equal(5, queue.Size())
|
assert.Equal(5, queue.Size())
|
||||||
|
|
||||||
err := queue.Enqueue(6)
|
err = queue.Enqueue(6)
|
||||||
assert.IsNotNil(err)
|
assert.IsNotNil(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularQueue_Dequeue(t *testing.T) {
|
func TestCircularQueue_Dequeue(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](4)
|
||||||
assert.Equal(true, queue.IsEmpty())
|
assert.Equal(true, queue.IsEmpty())
|
||||||
|
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
queue.Enqueue(2)
|
assert.IsNil(err)
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
err = queue.Enqueue(2)
|
||||||
queue.Enqueue(5)
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
val, err := queue.Dequeue()
|
val, err := queue.Dequeue()
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
@@ -43,11 +55,7 @@ func TestCircularQueue_Dequeue(t *testing.T) {
|
|||||||
assert.Equal(false, queue.IsFull())
|
assert.Equal(false, queue.IsFull())
|
||||||
|
|
||||||
val, _ = queue.Dequeue()
|
val, _ = queue.Dequeue()
|
||||||
queue.Print()
|
|
||||||
assert.Equal(2, *val)
|
assert.Equal(2, *val)
|
||||||
|
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Print()
|
|
||||||
assert.Equal(false, queue.IsFull())
|
assert.Equal(false, queue.IsFull())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,55 +63,52 @@ func TestCircularQueue_Front(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestCircularQueue_Front")
|
assert := internal.NewAssert(t, "TestCircularQueue_Front")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](6)
|
||||||
queue.Enqueue(1)
|
|
||||||
queue.Enqueue(2)
|
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
queue.Dequeue()
|
err = queue.Enqueue(2)
|
||||||
queue.Dequeue()
|
assert.IsNil(err)
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Enqueue(7)
|
|
||||||
|
|
||||||
queue.Print()
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
val := queue.Front()
|
val := queue.Front()
|
||||||
assert.Equal(3, val)
|
assert.IsNil(err)
|
||||||
assert.Equal(5, queue.Size())
|
assert.Equal(1, val)
|
||||||
|
assert.Equal(3, queue.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularQueue_Back(t *testing.T) {
|
func TestCircularQueue_Back(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_Back")
|
assert := internal.NewAssert(t, "TestCircularQueue_Back")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](3)
|
||||||
assert.Equal(true, queue.IsEmpty())
|
assert.Equal(true, queue.IsEmpty())
|
||||||
|
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
queue.Enqueue(2)
|
assert.IsNil(err)
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err = queue.Enqueue(2)
|
||||||
assert.Equal(5, queue.Back())
|
assert.IsNil(err)
|
||||||
|
|
||||||
queue.Dequeue()
|
assert.Equal(2, queue.Back())
|
||||||
queue.Dequeue()
|
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Enqueue(7)
|
|
||||||
|
|
||||||
queue.Print()
|
val, _ := queue.Dequeue()
|
||||||
assert.Equal(7, queue.Back())
|
assert.Equal(1, *val)
|
||||||
|
|
||||||
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(3, queue.Back())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularQueue_Contain(t *testing.T) {
|
func TestCircularQueue_Contain(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](2)
|
queue := NewCircularQueue[int](2)
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal(true, queue.Contain(1))
|
assert.Equal(true, queue.Contain(1))
|
||||||
assert.Equal(false, queue.Contain(2))
|
assert.Equal(false, queue.Contain(2))
|
||||||
}
|
}
|
||||||
@@ -115,7 +120,9 @@ func TestCircularQueue_Clear(t *testing.T) {
|
|||||||
assert.Equal(true, queue.IsEmpty())
|
assert.Equal(true, queue.IsEmpty())
|
||||||
assert.Equal(0, queue.Size())
|
assert.Equal(0, queue.Size())
|
||||||
|
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal(false, queue.IsEmpty())
|
assert.Equal(false, queue.IsEmpty())
|
||||||
assert.Equal(1, queue.Size())
|
assert.Equal(1, queue.Size())
|
||||||
|
|
||||||
@@ -127,22 +134,12 @@ func TestCircularQueue_Clear(t *testing.T) {
|
|||||||
func TestCircularQueue_Data(t *testing.T) {
|
func TestCircularQueue_Data(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_Data")
|
assert := internal.NewAssert(t, "TestCircularQueue_Data")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](3)
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
queue.Enqueue(2)
|
assert.IsNil(err)
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err = queue.Enqueue(2)
|
||||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
assert.IsNil(err)
|
||||||
|
|
||||||
queue.Dequeue()
|
|
||||||
queue.Dequeue()
|
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Enqueue(7)
|
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
|
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2}, queue.Data())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ func TestLinkedQueue_Enqueue(t *testing.T) {
|
|||||||
queue.Enqueue(2)
|
queue.Enqueue(2)
|
||||||
queue.Enqueue(3)
|
queue.Enqueue(3)
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||||
assert.Equal(3, queue.Size())
|
assert.Equal(3, queue.Size())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,19 +23,24 @@ func TestPriorityQueue_Enqueue(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
|
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
|
||||||
|
|
||||||
comparator := &intComparator{}
|
comparator := &intComparator{}
|
||||||
pq := NewPriorityQueue[int](10, comparator)
|
pq := NewPriorityQueue[int](3, comparator)
|
||||||
|
|
||||||
assert.Equal(true, pq.IsEmpty())
|
assert.Equal(true, pq.IsEmpty())
|
||||||
assert.Equal(false, pq.IsFull())
|
assert.Equal(false, pq.IsFull())
|
||||||
|
|
||||||
for i := 1; i < 11; i++ {
|
err := pq.Enqueue(1)
|
||||||
pq.Enqueue(i)
|
assert.IsNil(err)
|
||||||
}
|
|
||||||
|
err = pq.Enqueue(2)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = pq.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal(true, pq.IsFull())
|
assert.Equal(true, pq.IsFull())
|
||||||
|
|
||||||
queueData := pq.Data()
|
queueData := pq.Data()
|
||||||
assert.Equal([]int{10, 9, 6, 7, 8, 2, 5, 1, 4, 3}, queueData)
|
assert.Equal([]int{3, 1, 2}, queueData)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,22 +48,23 @@ func TestPriorityQueue_Dequeue(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
|
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
|
||||||
|
|
||||||
comparator := &intComparator{}
|
comparator := &intComparator{}
|
||||||
pq := NewPriorityQueue[int](10, comparator)
|
pq := NewPriorityQueue[int](3, comparator)
|
||||||
|
|
||||||
_, ok := pq.Dequeue()
|
_, ok := pq.Dequeue()
|
||||||
assert.Equal(false, ok)
|
assert.Equal(false, ok)
|
||||||
|
|
||||||
for i := 1; i < 11; i++ {
|
err := pq.Enqueue(1)
|
||||||
pq.Enqueue(i)
|
assert.IsNil(err)
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(10, pq.Size())
|
err = pq.Enqueue(2)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = pq.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(3, pq.Size())
|
||||||
|
|
||||||
val, ok := pq.Dequeue()
|
val, ok := pq.Dequeue()
|
||||||
assert.Equal(true, ok)
|
assert.Equal(true, ok)
|
||||||
assert.Equal(10, val)
|
assert.Equal(3, val)
|
||||||
|
|
||||||
assert.Equal([]int{9, 8, 6, 7, 3, 2, 5, 1, 4}, pq.Data())
|
|
||||||
|
|
||||||
assert.Equal(9, pq.Size())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ func TestLinkedStack_Push(t *testing.T) {
|
|||||||
stack.Push(2)
|
stack.Push(2)
|
||||||
stack.Push(3)
|
stack.Push(3)
|
||||||
|
|
||||||
stack.Print()
|
|
||||||
|
|
||||||
expected := []int{3, 2, 1}
|
expected := []int{3, 2, 1}
|
||||||
values := stack.Data()
|
values := stack.Data()
|
||||||
size := stack.Size()
|
size := stack.Size()
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ func TestBSTree_Insert(t *testing.T) {
|
|||||||
bstree.Insert(5)
|
bstree.Insert(5)
|
||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||||
@@ -86,8 +84,6 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
|||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
|
|
||||||
acturl := bstree.LevelOrderTraverse()
|
acturl := bstree.LevelOrderTraverse()
|
||||||
t.Log(acturl)
|
t.Log(acturl)
|
||||||
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
||||||
@@ -103,10 +99,8 @@ func TestBSTree_Delete(t *testing.T) {
|
|||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
|
|
||||||
bstree.Delete(4)
|
bstree.Delete(4)
|
||||||
bstree.Print()
|
|
||||||
acturl1 := bstree.InOrderTraverse()
|
acturl1 := bstree.InOrderTraverse()
|
||||||
t.Log(acturl1)
|
t.Log(acturl1)
|
||||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||||
@@ -129,8 +123,6 @@ func TestBSTree_Depth(t *testing.T) {
|
|||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
|
|
||||||
assert.Equal(bstree.Depth(), 4)
|
assert.Equal(bstree.Depth(), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +142,6 @@ func TestBSTree_IsSubTree(t *testing.T) {
|
|||||||
subTree.Insert(4)
|
subTree.Insert(4)
|
||||||
subTree.Insert(6)
|
subTree.Insert(6)
|
||||||
|
|
||||||
subTree.Print()
|
|
||||||
|
|
||||||
assert.Equal(true, superTree.HasSubTree(subTree))
|
assert.Equal(true, superTree.HasSubTree(subTree))
|
||||||
assert.Equal(false, subTree.HasSubTree(superTree))
|
assert.Equal(false, subTree.HasSubTree(superTree))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,35 +38,35 @@ func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
// func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||||
if node == nil {
|
// if node == nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
fmt.Printf("%v, ", node.Value)
|
// fmt.Printf("%v, ", node.Value)
|
||||||
preOrderPrint(node.Left)
|
// preOrderPrint(node.Left)
|
||||||
preOrderPrint(node.Right)
|
// preOrderPrint(node.Right)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
// func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||||
if node == nil {
|
// if node == nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
preOrderPrint(node.Left)
|
// postOrderPrint(node.Left)
|
||||||
preOrderPrint(node.Right)
|
// postOrderPrint(node.Right)
|
||||||
fmt.Printf("%v, ", node.Value)
|
// fmt.Printf("%v, ", node.Value)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
// func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||||
if node == nil {
|
// if node == nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
inOrderPrint(node.Left)
|
// inOrderPrint(node.Left)
|
||||||
fmt.Printf("%v, ", node.Value)
|
// fmt.Printf("%v, ", node.Value)
|
||||||
inOrderPrint(node.Right)
|
// inOrderPrint(node.Right)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
|
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
|
||||||
var q []*datastructure.TreeNode[T] // queue
|
var q []*datastructure.TreeNode[T] // queue
|
||||||
|
|||||||
@@ -132,12 +132,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||||
<p>Insert value into singly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
<p>Insert value into singly linklist at index, param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -152,6 +152,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewSinglyLink[int]()
|
lk := link.NewSinglyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -228,12 +230,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
<p>Delete value at specific index, param `index` should be [0, len(SinglyLink)-1]</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -253,9 +255,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -268,7 +269,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
func (link *SinglyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -288,9 +289,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -304,7 +304,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
func (link *SinglyLink[T]) DeleteAtTail()
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -323,9 +323,8 @@ func main() {
|
|||||||
lk.InsertAtTail(2)
|
lk.InsertAtTail(2)
|
||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
|
|
||||||
err := lk.DeleteAtTail()
|
lk.DeleteAtTail()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -628,12 +627,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||||
<p>Insert value into doubly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
<p>Insert value into doubly linklist at index, param `index` should between [0, len(DoublyLink)], if index do not meet the conditions, do nothing</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -648,6 +647,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewDoublyLink[int]()
|
lk := link.NewDoublyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -724,12 +725,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
<p>Delete value at specific index, param `index` should be [0, len(DoublyLink)-1]</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -749,9 +750,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -764,7 +764,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
func (link *DoublyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -784,9 +784,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -152,6 +152,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewSinglyLink[int]()
|
lk := link.NewSinglyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -233,7 +235,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -253,9 +255,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -268,7 +269,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
func (link *SinglyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -288,9 +289,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -304,7 +304,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
func (link *SinglyLink[T]) DeleteAtTail()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -323,9 +323,8 @@ func main() {
|
|||||||
lk.InsertAtTail(2)
|
lk.InsertAtTail(2)
|
||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
|
|
||||||
err := lk.DeleteAtTail()
|
lk.DeleteAtTail()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -633,7 +632,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -648,6 +647,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewDoublyLink[int]()
|
lk := link.NewDoublyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -729,7 +730,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -749,9 +750,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -764,7 +764,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
func (link *DoublyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -784,9 +784,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -800,7 +799,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAtTail() error
|
func (link *DoublyLink[T]) DeleteAtTail()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -819,9 +818,8 @@ func main() {
|
|||||||
lk.InsertAtTail(2)
|
lk.InsertAtTail(2)
|
||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
|
|
||||||
err := lk.DeleteAtTail()
|
lk.DeleteAtTail()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -28,13 +28,12 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Comma">Comma</span>
|
### <span id="Comma">Comma</span>
|
||||||
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
|
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
|
||||||
Param should be number or numberic string.</p>
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Comma(v any, symbol string) string
|
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Comma">Comma</span>
|
### <span id="Comma">Comma</span>
|
||||||
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
|
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Comma(v any, symbol string) string
|
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import (
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import (
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -1138,7 +1138,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
|
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|||||||
@@ -1135,7 +1135,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
|
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|||||||
116
docs/strutil.md
116
docs/strutil.md
@@ -28,12 +28,14 @@ import (
|
|||||||
- [Capitalize](#Capitalize)
|
- [Capitalize](#Capitalize)
|
||||||
- [IsString](#IsString)
|
- [IsString](#IsString)
|
||||||
- [KebabCase](#KebabCase)
|
- [KebabCase](#KebabCase)
|
||||||
|
- [UpperKebabCase](#UpperKebabCase)
|
||||||
- [LowerFirst](#LowerFirst)
|
- [LowerFirst](#LowerFirst)
|
||||||
- [UpperFirst](#UpperFirst)
|
- [UpperFirst](#UpperFirst)
|
||||||
- [PadEnd](#PadEnd)
|
- [PadEnd](#PadEnd)
|
||||||
- [PadStart](#PadStart)
|
- [PadStart](#PadStart)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
- [SnakeCase](#SnakeCase)
|
- [SnakeCase](#SnakeCase)
|
||||||
|
- [UpperSnakeCase](#UpperSnakeCase)
|
||||||
- [SplitEx](#SplitEx)
|
- [SplitEx](#SplitEx)
|
||||||
- [Wrap](#Wrap)
|
- [Wrap](#Wrap)
|
||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
@@ -165,10 +167,8 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="CamelCase">CamelCase</span>
|
### <span id="CamelCase">CamelCase</span>
|
||||||
<p>Covert string to camelCase string.</p>
|
<p>Coverts string to camelCase string, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -195,6 +195,75 @@ func main() {
|
|||||||
|
|
||||||
s4 := strutil.CamelCase("foo bar")
|
s4 := strutil.CamelCase("foo bar")
|
||||||
fmt.Println(s4) //fooBar
|
fmt.Println(s4) //fooBar
|
||||||
|
|
||||||
|
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s4) //foo11Bar
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="KebabCase">KebabCase</span>
|
||||||
|
<p>KebabCase covert string to kebab-case, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func KebabCase(s string) string
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.KebabCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //foo-bar
|
||||||
|
|
||||||
|
s2 := strutil.KebabCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //foo-bar
|
||||||
|
|
||||||
|
s3 := strutil.KebabCase("fooBar")
|
||||||
|
fmt.Println(s3) //foo-bar
|
||||||
|
|
||||||
|
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //foo-bar
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||||
|
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func KebabCase(s string) string
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO-BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO-BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperKebabCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO-BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO-BAR
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -457,7 +526,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SnakeCase">SnakeCase</span>
|
### <span id="SnakeCase">SnakeCase</span>
|
||||||
<p>Covert string to snake_case.</p>
|
<p>Coverts string to snake_case, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -483,14 +552,47 @@ func main() {
|
|||||||
fmt.Println(s3) //foo_bar
|
fmt.Println(s3) //foo_bar
|
||||||
|
|
||||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||||
fmt.Println(s4) //f_o_o_b_a_r
|
fmt.Println(s4) //foo_bar
|
||||||
|
|
||||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
fmt.Println(s5) //foo_1_1_bar
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||||
|
<p>Coverts string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SnakeCase(s string) string
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO_BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO_BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperSnakeCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO_BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO_BAR
|
||||||
|
|
||||||
|
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s5) //FOO_1_1_BAR
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="SplitEx">SplitEx</span>
|
### <span id="SplitEx">SplitEx</span>
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ import (
|
|||||||
- [Capitalize](#Capitalize)
|
- [Capitalize](#Capitalize)
|
||||||
- [IsString](#IsString)
|
- [IsString](#IsString)
|
||||||
- [KebabCase](#KebabCase)
|
- [KebabCase](#KebabCase)
|
||||||
|
- [UpperKebabCase](#UpperKebabCase)
|
||||||
- [LowerFirst](#LowerFirst)
|
- [LowerFirst](#LowerFirst)
|
||||||
- [UpperFirst](#UpperFirst)
|
- [UpperFirst](#UpperFirst)
|
||||||
- [PadEnd](#PadEnd)
|
- [PadEnd](#PadEnd)
|
||||||
- [PadStart](#PadStart)
|
- [PadStart](#PadStart)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
- [SnakeCase](#SnakeCase)
|
- [SnakeCase](#SnakeCase)
|
||||||
|
- [UpperSnakeCase](#UpperSnakeCase)
|
||||||
- [SplitEx](#SplitEx)
|
- [SplitEx](#SplitEx)
|
||||||
- [Wrap](#Wrap)
|
- [Wrap](#Wrap)
|
||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
@@ -169,7 +171,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="CamelCase">CamelCase</span>
|
### <span id="CamelCase">CamelCase</span>
|
||||||
<p>将字符串转换为驼峰式字符串</p>
|
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -196,6 +198,9 @@ func main() {
|
|||||||
|
|
||||||
s4 := strutil.CamelCase("foo bar")
|
s4 := strutil.CamelCase("foo bar")
|
||||||
fmt.Println(s4) //fooBar
|
fmt.Println(s4) //fooBar
|
||||||
|
|
||||||
|
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s4) //foo11Bar
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -261,7 +266,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="KebabCase">KebabCase</span>
|
### <span id="KebabCase">KebabCase</span>
|
||||||
<p>将字符串转换为kebab-case</p>
|
<p>将字符串转换为kebab-case, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -287,7 +292,40 @@ func main() {
|
|||||||
fmt.Println(s3) //foo-bar
|
fmt.Println(s3) //foo-bar
|
||||||
|
|
||||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||||
fmt.Println(s4) //f-o-o-b-a-r
|
fmt.Println(s4) //foo-bar
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||||
|
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func KebabCase(s string) string
|
||||||
|
```
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO-BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO-BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperKebabCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO-BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO-BAR
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -458,7 +496,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SnakeCase">SnakeCase</span>
|
### <span id="SnakeCase">SnakeCase</span>
|
||||||
<p>将字符串转换为snake_case形式</p>
|
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -484,10 +522,45 @@ func main() {
|
|||||||
fmt.Println(s3) //foo_bar
|
fmt.Println(s3) //foo_bar
|
||||||
|
|
||||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||||
fmt.Println(s4) //f_o_o_b_a_r
|
fmt.Println(s4) //foo_bar
|
||||||
|
|
||||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
fmt.Println(s5) //foo_1_1_bar
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||||
|
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SnakeCase(s string) string
|
||||||
|
```
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO_BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO_BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperSnakeCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO_BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO_BAR
|
||||||
|
|
||||||
|
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s5) //FOO_1_1_BAR
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="ExecCommand">CompareOsEnv</span>
|
### <span id="ExecCommand">CompareOsEnv</span>
|
||||||
<p>Use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
|
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -227,10 +227,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out, errout, err := system.ExecCommand("ls")
|
// linux or mac
|
||||||
fmt.Println(out)
|
stdout, stderr, err := system.ExecCommand("ls")
|
||||||
fmt.Println(errout)
|
fmt.Println("std out: ", stdout)
|
||||||
fmt.Println(err)
|
fmt.Println("std err: ", stderr)
|
||||||
|
assert.Equal("", stderr)
|
||||||
|
|
||||||
|
// windows
|
||||||
|
stdout, stderr, err = system.ExecCommand("dir")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
|
||||||
|
// error command
|
||||||
|
stdout, stderr, err = system.ExecCommand("abc")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="ExecCommand">ExecCommand</span>
|
### <span id="ExecCommand">ExecCommand</span>
|
||||||
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令。</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -228,10 +228,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out, errout, err := system.ExecCommand("ls")
|
// linux or mac
|
||||||
fmt.Println(out)
|
stdout, stderr, err := system.ExecCommand("ls")
|
||||||
fmt.Println(errout)
|
fmt.Println("std out: ", stdout)
|
||||||
fmt.Println(err)
|
fmt.Println("std err: ", stderr)
|
||||||
|
assert.Equal("", stderr)
|
||||||
|
|
||||||
|
// windows
|
||||||
|
stdout, stderr, err = system.ExecCommand("dir")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
|
||||||
|
// error command
|
||||||
|
stdout, stderr, err = system.ExecCommand("abc")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import (
|
|||||||
- [IsUrl](#IsUrl)
|
- [IsUrl](#IsUrl)
|
||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
- [IsZeroValue](#IsZeroValue)
|
- [IsZeroValue](#IsZeroValue)
|
||||||
|
- [IsGBK](#IsGBK)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -821,7 +822,34 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="IsGBK">IsGBK</span>
|
||||||
|
<p>Checks if data encoding is gbk(Chinese character internal code extension specification). this function is implemented by whether double bytes fall within the encoding range of gbk,while each byte of utf-8 encoding format falls within the encoding range of gbk.Therefore, utf8.valid() should be called first to check whether it is not utf-8 encoding and then call IsGBK() to check gbk encoding. like the example.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsGBK(data []byte) bool
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := []byte("你好")
|
||||||
|
|
||||||
|
// check utf8 first
|
||||||
|
if utf8.Valid(data) {
|
||||||
|
fmt.Println("data encoding is utf-8")
|
||||||
|
}else if(validator.IsGBK(data)) {
|
||||||
|
fmt.Println("data encoding is GBK")
|
||||||
|
}
|
||||||
|
fmt.Println("data encoding is unknown")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import (
|
|||||||
- [IsUrl](#IsUrl)
|
- [IsUrl](#IsUrl)
|
||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
- [IsZeroValue](#IsZeroValue)
|
- [IsZeroValue](#IsZeroValue)
|
||||||
|
- [IsGBK](#IsGBK)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -820,3 +821,31 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsGBK">IsGBK</span>
|
||||||
|
<p>检查数据编码是否为gbk(汉字内部代码扩展规范)。该函数的实现取决于双字节是否在gbk的编码范围内,而utf-8编码格式的每个字节都在gbk编码范围内。因此,应该首先调用utf8.valid检查它是否是utf-8编码,然后调用IsGBK检查gbk编码。如示例所示。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsGBK(data []byte) bool
|
||||||
|
```
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := []byte("你好")
|
||||||
|
|
||||||
|
// 先检查utf8编码
|
||||||
|
if utf8.Valid(data) {
|
||||||
|
fmt.Println("data encoding is utf-8")
|
||||||
|
}else if(validator.IsGBK(data)) {
|
||||||
|
fmt.Println("data encoding is GBK")
|
||||||
|
}
|
||||||
|
fmt.Println("data encoding is unknown")
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -78,13 +77,16 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
|
|||||||
var tmp = make([]byte, 1024*4)
|
var tmp = make([]byte, 1024*4)
|
||||||
for {
|
for {
|
||||||
n, err := srcFile.Read(tmp)
|
n, err := srcFile.Read(tmp)
|
||||||
distFile.Write(tmp[:n])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, err = distFile.Write(tmp[:n])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +104,7 @@ func ClearFile(path string) error {
|
|||||||
|
|
||||||
//ReadFileToString return string of file content
|
//ReadFileToString return string of file content
|
||||||
func ReadFileToString(path string) (string, error) {
|
func ReadFileToString(path string) (string, error) {
|
||||||
bytes, err := ioutil.ReadFile(path)
|
bytes, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -141,7 +143,7 @@ func ListFileNames(path string) ([]string, error) {
|
|||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fs, err := ioutil.ReadDir(path)
|
fs, err := os.ReadDir(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
}
|
}
|
||||||
@@ -172,7 +174,7 @@ func Zip(fpath string, destPath string) error {
|
|||||||
archive := zip.NewWriter(zipFile)
|
archive := zip.NewWriter(zipFile)
|
||||||
defer archive.Close()
|
defer archive.Close()
|
||||||
|
|
||||||
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
err = filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -209,6 +211,10 @@ func Zip(fpath string, destPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +235,13 @@ func UnZip(zipFile string, destPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f.FileInfo().IsDir() {
|
if f.FileInfo().IsDir() {
|
||||||
os.MkdirAll(path, os.ModePerm)
|
err = os.MkdirAll(path, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
err = os.MkdirAll(filepath.Dir(path), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ func TestCreateFile(t *testing.T) {
|
|||||||
f := "./text.txt"
|
f := "./text.txt"
|
||||||
if CreateFile(f) {
|
if CreateFile(f) {
|
||||||
file, err := os.Open(f)
|
file, err := os.Open(f)
|
||||||
defer file.Close()
|
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
assert.Equal(f, file.Name())
|
assert.Equal(f, file.Name())
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
} else {
|
} else {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -113,7 +114,11 @@ func TestReadFileToString(t *testing.T) {
|
|||||||
|
|
||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
f.WriteString("hello world")
|
|
||||||
|
_, err := f.WriteString("hello world")
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
|
||||||
content, _ := ReadFileToString(path)
|
content, _ := ReadFileToString(path)
|
||||||
assert.Equal("hello world", content)
|
assert.Equal("hello world", content)
|
||||||
@@ -130,9 +135,12 @@ func TestClearFile(t *testing.T) {
|
|||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
f.WriteString("hello world")
|
_, err := f.WriteString("hello world")
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
|
||||||
err := ClearFile(path)
|
err = ClearFile(path)
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
|
|
||||||
content, _ := ReadFileToString(path)
|
content, _ := ReadFileToString(path)
|
||||||
@@ -148,8 +156,13 @@ func TestReadFileByLine(t *testing.T) {
|
|||||||
CreateFile(path)
|
CreateFile(path)
|
||||||
|
|
||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
f.WriteString("hello\nworld")
|
|
||||||
|
_, err := f.WriteString("hello\nworld")
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
|
||||||
expected := []string{"hello", "world"}
|
expected := []string{"hello", "world"}
|
||||||
actual, _ := ReadFileByLine(path)
|
actual, _ := ReadFileByLine(path)
|
||||||
@@ -166,10 +179,14 @@ func TestZipAndUnZip(t *testing.T) {
|
|||||||
|
|
||||||
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
|
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
file.WriteString("hello\nworld")
|
|
||||||
|
_, err := file.WriteString("hello\nworld")
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
zipFile := "./text.zip"
|
zipFile := "./text.zip"
|
||||||
err := Zip(srcFile, zipFile)
|
err = Zip(srcFile, zipFile)
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
|
|
||||||
unZipPath := "./unzip"
|
unZipPath := "./unzip"
|
||||||
|
|||||||
@@ -4,14 +4,25 @@
|
|||||||
// Package formatter implements some functions to format string, struct.
|
// Package formatter implements some functions to format string, struct.
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Comma add comma to a number value by every 3 numbers from right. ahead by symbol char.
|
||||||
|
// if value is invalid number string eg "aa", return empty string
|
||||||
|
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
||||||
|
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string {
|
||||||
|
s, err := numberToString(value)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
|
|
||||||
func Comma(v any, symbol string) string {
|
|
||||||
s := numString(v)
|
|
||||||
dotIndex := strings.Index(s, ".")
|
dotIndex := strings.Index(s, ".")
|
||||||
if dotIndex != -1 {
|
if dotIndex != -1 {
|
||||||
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbol + commaString(s)
|
return symbol + commaString(s)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,27 +14,34 @@ func commaString(s string) string {
|
|||||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func numString(value any) string {
|
func numberToString(value any) (string, error) {
|
||||||
switch reflect.TypeOf(value).Kind() {
|
switch reflect.TypeOf(value).Kind() {
|
||||||
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
return fmt.Sprintf("%v", value)
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return fmt.Sprintf("%v", value), nil
|
||||||
|
|
||||||
|
// todo: need to handle 12345678.9 => 1.23456789e+07
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return fmt.Sprintf("%v", value), nil
|
||||||
|
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
{
|
{
|
||||||
sv := fmt.Sprintf("%v", value)
|
sv := fmt.Sprintf("%v", value)
|
||||||
if strings.Contains(sv, ".") {
|
if strings.Contains(sv, ".") {
|
||||||
_, err := strconv.ParseFloat(sv, 64)
|
_, err := strconv.ParseFloat(sv, 64)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
return sv
|
return "", err
|
||||||
}
|
}
|
||||||
|
return sv, nil
|
||||||
} else {
|
} else {
|
||||||
_, err := strconv.ParseInt(sv, 10, 64)
|
_, err := strconv.ParseInt(sv, 10, 64)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
return sv
|
return "", nil
|
||||||
}
|
}
|
||||||
|
return sv, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,16 @@ func TestComma(t *testing.T) {
|
|||||||
assert.Equal("", Comma("", ""))
|
assert.Equal("", Comma("", ""))
|
||||||
assert.Equal("", Comma("aa", ""))
|
assert.Equal("", Comma("aa", ""))
|
||||||
assert.Equal("", Comma("aa.a", ""))
|
assert.Equal("", Comma("aa.a", ""))
|
||||||
assert.Equal("", Comma([]int{1}, ""))
|
|
||||||
assert.Equal("123", Comma("123", ""))
|
assert.Equal("123", Comma("123", ""))
|
||||||
assert.Equal("12,345", Comma("12345", ""))
|
assert.Equal("12,345", Comma("12345", ""))
|
||||||
|
assert.Equal("12,345.6789", Comma("12345.6789", ""))
|
||||||
|
assert.Equal("123,456,789,000", Comma("123456789000", ""))
|
||||||
|
|
||||||
assert.Equal("12,345", Comma(12345, ""))
|
assert.Equal("12,345", Comma(12345, ""))
|
||||||
assert.Equal("$12,345", Comma(12345, "$"))
|
assert.Equal("$12,345", Comma(12345, "$"))
|
||||||
assert.Equal("¥12,345", Comma(12345, "¥"))
|
assert.Equal("¥12,345", Comma(12345, "¥"))
|
||||||
assert.Equal("12,345.6789", Comma(12345.6789, ""))
|
assert.Equal("12,345.6789", Comma(12345.6789, ""))
|
||||||
|
assert.Equal("12,345.6789", Comma(+12345.6789, ""))
|
||||||
|
// assert.Equal("12,345,678.9", Comma(12345678.9, ""))
|
||||||
|
assert.Equal("123,456,789,000", Comma(123456789000, ""))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,11 +84,9 @@ func Debounced(fn func(), duration time.Duration) func() {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
<-timer.C
|
||||||
case <-timer.C:
|
|
||||||
go fn()
|
go fn()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return func() { timer.Reset(duration) }
|
return func() { timer.Reset(duration) }
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -1,3 +1,8 @@
|
|||||||
module github.com/duke-git/lancet/v2
|
module github.com/duke-git/lancet/v2
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a
|
||||||
|
golang.org/x/text v0.5.0
|
||||||
|
)
|
||||||
|
|||||||
4
go.sum
Normal file
4
go.sum
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
|
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||||
|
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
@@ -3,14 +3,16 @@
|
|||||||
|
|
||||||
// Package iterator provides a way to iterate over values stored in containers.
|
// Package iterator provides a way to iterate over values stored in containers.
|
||||||
// note:
|
// note:
|
||||||
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go.
|
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||||
package iterator
|
package iterator
|
||||||
|
|
||||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
import (
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
// Iterator supports iterating over a sequence of values of type `E`.
|
// Iterator supports iterating over a sequence of values of type `E`.
|
||||||
type Iterator[T any] interface {
|
type Iterator[T any] interface {
|
||||||
@@ -142,7 +144,7 @@ func (iter *sliceIterator[T]) Set(value T) {
|
|||||||
|
|
||||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
||||||
// exclusive by the step size. start should be less than end, step shoud be positive.
|
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||||
func FromRange[T lancetconstraints.Number](start, end, step T) Iterator[T] {
|
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) Iterator[T] {
|
||||||
if end < start {
|
if end < start {
|
||||||
panic("RangeIterator: start should be before end")
|
panic("RangeIterator: start should be before end")
|
||||||
} else if step <= 0 {
|
} else if step <= 0 {
|
||||||
@@ -152,15 +154,12 @@ func FromRange[T lancetconstraints.Number](start, end, step T) Iterator[T] {
|
|||||||
return &rangeIterator[T]{start: start, end: end, step: step}
|
return &rangeIterator[T]{start: start, end: end, step: step}
|
||||||
}
|
}
|
||||||
|
|
||||||
type rangeIterator[T lancetconstraints.Number] struct {
|
type rangeIterator[T constraints.Integer | constraints.Float] struct {
|
||||||
start, end, step T
|
start, end, step T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *rangeIterator[T]) HasNext() bool {
|
func (iter *rangeIterator[T]) HasNext() bool {
|
||||||
if iter.start >= iter.end {
|
return iter.start < iter.end
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *rangeIterator[T]) Next() (T, bool) {
|
func (iter *rangeIterator[T]) Next() (T, bool) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
// Package iterator provides a way to iterate over values stored in containers.
|
// Package iterator provides a way to iterate over values stored in containers.
|
||||||
// note:
|
// note:
|
||||||
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go.
|
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||||
|
|||||||
@@ -11,13 +11,3 @@ type Comparator interface {
|
|||||||
// Descending order: should return 1 -> v1 < v2, 0 -> v1 = v2, -1 -> v1 > v2
|
// Descending order: should return 1 -> v1 < v2, 0 -> v1 = v2, -1 -> v1 > v2
|
||||||
Compare(v1, v2 any) int
|
Compare(v1, v2 any) int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number contains all types of number and uintptr, used for generics constraint
|
|
||||||
type Number interface {
|
|
||||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ordered is a constraint that permits any ordered type: any type that supports the operators < <= >= >
|
|
||||||
type Ordered interface {
|
|
||||||
Number | ~string
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
reduceMaps := make([]map[K]V, 2, 2)
|
reduceMaps := make([]map[K]V, 2)
|
||||||
result = reducer(maps[0], maps[1])
|
result = reducer(maps[0], maps[1])
|
||||||
|
|
||||||
for i := 2; i < len(maps); i++ {
|
for i := 2; i < len(maps); i++ {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Exponent calculate x^n
|
// Exponent calculate x^n
|
||||||
@@ -94,7 +94,7 @@ func TruncRound(x float64, n int) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Max return max value of params
|
// Max return max value of params
|
||||||
func Max[T lancetconstraints.Number](numbers ...T) T {
|
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||||
max := numbers[0]
|
max := numbers[0]
|
||||||
|
|
||||||
for _, v := range numbers {
|
for _, v := range numbers {
|
||||||
@@ -128,7 +128,7 @@ func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Min return min value of params
|
// Min return min value of params
|
||||||
func Min[T lancetconstraints.Number](numbers ...T) T {
|
func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||||
min := numbers[0]
|
min := numbers[0]
|
||||||
|
|
||||||
for _, v := range numbers {
|
for _, v := range numbers {
|
||||||
@@ -161,8 +161,8 @@ func MinBy[T any](slice []T, comparator func(T, T) bool) T {
|
|||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
|
|
||||||
// Average return average value of params
|
// Average return average value of numbers
|
||||||
func Average[T lancetconstraints.Number](numbers ...T) T {
|
func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||||
var sum T
|
var sum T
|
||||||
n := T(len(numbers))
|
n := T(len(numbers))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -108,7 +108,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
|||||||
|
|
||||||
client.setTLS(rawUrl)
|
client.setTLS(rawUrl)
|
||||||
client.setHeader(req, request.Headers)
|
client.setHeader(req, request.Headers)
|
||||||
client.setQueryParam(req, rawUrl, request.QueryParams)
|
|
||||||
|
err = client.setQueryParam(req, rawUrl, request.QueryParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if request.FormData != nil {
|
if request.FormData != nil {
|
||||||
client.setFormData(req, request.FormData)
|
client.setFormData(req, request.FormData)
|
||||||
@@ -177,7 +181,7 @@ func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryP
|
|||||||
|
|
||||||
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
|
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
|
||||||
formData := []byte(values.Encode())
|
formData := []byte(values.Encode())
|
||||||
req.Body = ioutil.NopCloser(bytes.NewReader(formData))
|
req.Body = io.NopCloser(bytes.NewReader(formData))
|
||||||
req.ContentLength = int64(len(formData))
|
req.ContentLength = int64(len(formData))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package netutil
|
package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -32,7 +32,10 @@ func TestHttpClient_Get(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var todo Todo
|
var todo Todo
|
||||||
httpClient.DecodeResponse(resp, &todo)
|
err = httpClient.DecodeResponse(resp, &todo)
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
|
||||||
assert.Equal(1, todo.Id)
|
assert.Equal(1, todo.Id)
|
||||||
}
|
}
|
||||||
@@ -58,7 +61,7 @@ func TestHttpClent_Post(t *testing.T) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +93,6 @@ func TestStructToUrlValues(t *testing.T) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", string(body))
|
t.Log("response: ", string(body))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ package netutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
@@ -20,7 +21,7 @@ func TestHttpGet(t *testing.T) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ func TestHttpPost(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,23 +51,20 @@ func TestHttpPostFormData(t *testing.T) {
|
|||||||
// "Content-Type": "application/x-www-form-urlencoded",
|
// "Content-Type": "application/x-www-form-urlencoded",
|
||||||
"Content-Type": "multipart/form-data",
|
"Content-Type": "multipart/form-data",
|
||||||
}
|
}
|
||||||
type Todo struct {
|
|
||||||
UserId int `json:"userId"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
}
|
|
||||||
// postData := url.Values{}
|
|
||||||
// postData.Add("userId", "1")
|
|
||||||
// postData.Add("title", "TestAddToDo")
|
|
||||||
|
|
||||||
postData := make(map[string]string)
|
postData := url.Values{}
|
||||||
postData["userId"] = "1"
|
postData.Add("userId", "1")
|
||||||
postData["title"] = "title"
|
postData.Add("title", "TestToDo")
|
||||||
|
|
||||||
|
// postData := make(map[string]string)
|
||||||
|
// postData["userId"] = "1"
|
||||||
|
// postData["title"] = "title"
|
||||||
|
|
||||||
resp, err := HttpPost(apiUrl, header, postData, nil)
|
resp, err := HttpPost(apiUrl, header, postData, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +85,7 @@ func TestHttpPut(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +106,7 @@ func TestHttpPatch(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +116,7 @@ func TestHttpDelete(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package netutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -55,7 +55,7 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package netutil
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -173,7 +173,7 @@ func setBodyByte(req *http.Request, body any) error {
|
|||||||
if body != nil {
|
if body != nil {
|
||||||
switch b := body.(type) {
|
switch b := body.(type) {
|
||||||
case []byte:
|
case []byte:
|
||||||
req.Body = ioutil.NopCloser(bytes.NewReader(b))
|
req.Body = io.NopCloser(bytes.NewReader(b))
|
||||||
req.ContentLength = int64(len(b))
|
req.ContentLength = int64(len(b))
|
||||||
default:
|
default:
|
||||||
return errors.New("body type should be []byte")
|
return errors.New("body type should be []byte")
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a static variable to store the hash table.
|
||||||
|
// This variable has the same lifetime as the entire program and can be shared by functions that are called more than once.
|
||||||
|
var (
|
||||||
|
memoryHashMap = make(map[string]map[any]int)
|
||||||
|
memoryHashCounter = make(map[string]int)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Contain check if the target value is in the slice or not
|
// Contain check if the target value is in the slice or not
|
||||||
@@ -729,7 +736,7 @@ func Shuffle[T any](slice []T) []T {
|
|||||||
|
|
||||||
// Sort sorts a slice of any ordered type(number or string), use quick sort algrithm.
|
// Sort sorts a slice of any ordered type(number or string), use quick sort algrithm.
|
||||||
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`
|
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`
|
||||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string) {
|
func Sort[T constraints.Ordered](slice []T, sortOrder ...string) {
|
||||||
if len(sortOrder) > 0 && sortOrder[0] == "desc" {
|
if len(sortOrder) > 0 && sortOrder[0] == "desc" {
|
||||||
quickSort(slice, 0, len(slice)-1, "desc")
|
quickSort(slice, 0, len(slice)-1, "desc")
|
||||||
} else {
|
} else {
|
||||||
@@ -832,14 +839,44 @@ func Without[T comparable](slice []T, items ...T) []T {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// IndexOf returns the index at which the first occurrence of a item is found in a slice or return -1 if the item cannot be found.
|
// IndexOf returns the index at which the first occurrence of an item is found in a slice or return -1 if the item cannot be found.
|
||||||
func IndexOf[T comparable](slice []T, item T) int {
|
func IndexOf[T comparable](arr []T, val T) int {
|
||||||
for i, v := range slice {
|
limit := 10
|
||||||
if v == item {
|
// gets the hash value of the array as the key of the hash table.
|
||||||
return i
|
key := fmt.Sprintf("%p", arr)
|
||||||
|
// determines whether the hash table is empty. If so, the hash table is created.
|
||||||
|
if memoryHashMap[key] == nil {
|
||||||
|
memoryHashMap[key] = make(map[any]int)
|
||||||
|
// iterate through the array, adding the value and index of each element to the hash table.
|
||||||
|
for i := len(arr) - 1; i >= 0; i-- {
|
||||||
|
memoryHashMap[key][arr[i]] = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// update the hash table counter.
|
||||||
|
memoryHashCounter[key]++
|
||||||
|
|
||||||
|
// use the hash table to find the specified value. If found, the index is returned.
|
||||||
|
if index, ok := memoryHashMap[key][val]; ok {
|
||||||
|
// calculate the memory usage of the hash table.
|
||||||
|
size := len(memoryHashMap)
|
||||||
|
// If the memory usage of the hash table exceeds the memory limit, the hash table with the lowest counter is cleared.
|
||||||
|
if size > limit {
|
||||||
|
var minKey string
|
||||||
|
var minVal int
|
||||||
|
for k, v := range memoryHashCounter {
|
||||||
|
if k == key {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if minVal == 0 || v < minVal {
|
||||||
|
minKey = k
|
||||||
|
minVal = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(memoryHashMap, minKey)
|
||||||
|
delete(memoryHashCounter, minKey)
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sliceValue return the reflect value of a slice
|
// sliceValue return the reflect value of a slice
|
||||||
@@ -27,7 +27,7 @@ func sliceElemType(reflectType reflect.Type) reflect.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func quickSort[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) {
|
func quickSort[T constraints.Ordered](slice []T, lowIndex, highIndex int, order string) {
|
||||||
if lowIndex < highIndex {
|
if lowIndex < highIndex {
|
||||||
p := partitionOrderedSlice(slice, lowIndex, highIndex, order)
|
p := partitionOrderedSlice(slice, lowIndex, highIndex, order)
|
||||||
quickSort(slice, lowIndex, p-1, order)
|
quickSort(slice, lowIndex, p-1, order)
|
||||||
@@ -36,7 +36,7 @@ func quickSort[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// partitionOrderedSlice split ordered slice into two parts for quick sort
|
// partitionOrderedSlice split ordered slice into two parts for quick sort
|
||||||
func partitionOrderedSlice[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) int {
|
func partitionOrderedSlice[T constraints.Ordered](slice []T, lowIndex, highIndex int, order string) int {
|
||||||
p := slice[highIndex]
|
p := slice[highIndex]
|
||||||
i := lowIndex
|
i := lowIndex
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package slice
|
package slice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -669,8 +670,39 @@ func TestIndexOf(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestIndexOf")
|
assert := internal.NewAssert(t, "TestIndexOf")
|
||||||
|
|
||||||
arr := []string{"a", "a", "b", "c"}
|
arr := []string{"a", "a", "b", "c"}
|
||||||
|
key := fmt.Sprintf("%p", arr)
|
||||||
assert.Equal(0, IndexOf(arr, "a"))
|
assert.Equal(0, IndexOf(arr, "a"))
|
||||||
assert.Equal(-1, IndexOf(arr, "d"))
|
assert.Equal(-1, IndexOf(arr, "d"))
|
||||||
|
assert.Equal(2, memoryHashCounter[key])
|
||||||
|
|
||||||
|
arr1 := []int{1, 2, 3, 4, 5}
|
||||||
|
key1 := fmt.Sprintf("%p", arr1)
|
||||||
|
assert.Equal(3, IndexOf(arr1, 4))
|
||||||
|
assert.Equal(-1, IndexOf(arr1, 6))
|
||||||
|
assert.Equal(2, memoryHashCounter[key1])
|
||||||
|
|
||||||
|
arr2 := []float64{1.1, 2.2, 3.3, 4.4, 5.5}
|
||||||
|
key2 := fmt.Sprintf("%p", arr2)
|
||||||
|
assert.Equal(2, IndexOf(arr2, 3.3))
|
||||||
|
assert.Equal(3, IndexOf(arr2, 4.4))
|
||||||
|
assert.Equal(-1, IndexOf(arr2, 6.6))
|
||||||
|
assert.Equal(3, memoryHashCounter[key2])
|
||||||
|
|
||||||
|
for i := 0; i < 6; i++ {
|
||||||
|
a := []string{"a", "b", "c"}
|
||||||
|
IndexOf(a, "a")
|
||||||
|
IndexOf(a, "b")
|
||||||
|
}
|
||||||
|
minArr := []string{"c", "b", "a"}
|
||||||
|
minKey := fmt.Sprintf("%p", minArr)
|
||||||
|
assert.Equal(0, IndexOf(minArr, "c"))
|
||||||
|
|
||||||
|
arr3 := []string{"q", "w", "e"}
|
||||||
|
key3 := fmt.Sprintf("%p", arr3)
|
||||||
|
assert.Equal(1, IndexOf(arr3, "w"))
|
||||||
|
assert.Equal(-1, IndexOf(arr3, "r"))
|
||||||
|
assert.Equal(2, memoryHashCounter[key3])
|
||||||
|
assert.Equal(0, memoryHashCounter[minKey])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLastIndexOf(t *testing.T) {
|
func TestLastIndexOf(t *testing.T) {
|
||||||
|
|||||||
@@ -4,53 +4,41 @@
|
|||||||
package strutil
|
package strutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CamelCase covert string to camelCase string.
|
// CamelCase covert string to camelCase string.
|
||||||
|
// non letters and numbers will be ignored
|
||||||
|
// eg. "Foo-#1😄$_%^&*(1bar" => "foo11Bar"
|
||||||
func CamelCase(s string) string {
|
func CamelCase(s string) string {
|
||||||
if len(s) == 0 {
|
var builder strings.Builder
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
result := ""
|
strs := splitIntoStrings(s, false)
|
||||||
blankSpace := " "
|
for i, str := range strs {
|
||||||
regex, _ := regexp.Compile("[-_&]+")
|
|
||||||
ss := regex.ReplaceAllString(s, blankSpace)
|
|
||||||
for i, v := range strings.Split(ss, blankSpace) {
|
|
||||||
vv := []rune(v)
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if vv[i] >= 65 && vv[i] <= 96 {
|
builder.WriteString(strings.ToLower(str))
|
||||||
vv[0] += 32
|
|
||||||
}
|
|
||||||
result += string(vv)
|
|
||||||
} else {
|
} else {
|
||||||
result += Capitalize(v)
|
builder.WriteString(Capitalize(str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capitalize converts the first character of a string to upper case and the remaining to lower case.
|
// Capitalize converts the first character of a string to upper case and the remaining to lower case.
|
||||||
func Capitalize(s string) string {
|
func Capitalize(s string) string {
|
||||||
if len(s) == 0 {
|
result := make([]rune, len(s))
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]rune, len(s))
|
|
||||||
for i, v := range s {
|
for i, v := range s {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
out[i] = unicode.ToUpper(v)
|
result[i] = unicode.ToUpper(v)
|
||||||
} else {
|
} else {
|
||||||
out[i] = unicode.ToLower(v)
|
result[i] = unicode.ToLower(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(out)
|
return string(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpperFirst converts the first character of string to upper case.
|
// UpperFirst converts the first character of string to upper case.
|
||||||
@@ -116,46 +104,34 @@ func PadStart(source string, size int, padStr string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// KebabCase covert string to kebab-case
|
// KebabCase covert string to kebab-case
|
||||||
|
// non letters and numbers will be ignored
|
||||||
|
// eg. "Foo-#1😄$_%^&*(1bar" => "foo-1-1-bar"
|
||||||
func KebabCase(s string) string {
|
func KebabCase(s string) string {
|
||||||
if len(s) == 0 {
|
result := splitIntoStrings(s, false)
|
||||||
return ""
|
return strings.Join(result, "-")
|
||||||
}
|
|
||||||
|
|
||||||
regex := regexp.MustCompile(`[\W|_]+`)
|
|
||||||
blankSpace := " "
|
|
||||||
match := regex.ReplaceAllString(s, blankSpace)
|
|
||||||
rs := strings.Split(match, blankSpace)
|
|
||||||
|
|
||||||
var result []string
|
|
||||||
for _, v := range rs {
|
|
||||||
splitWords := splitWordsToLower(v)
|
|
||||||
if len(splitWords) > 0 {
|
|
||||||
result = append(result, splitWords...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpperKebabCase covert string to upper KEBAB-CASE
|
||||||
|
// non letters and numbers will be ignored
|
||||||
|
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO-1-1-BAR"
|
||||||
|
func UpperKebabCase(s string) string {
|
||||||
|
result := splitIntoStrings(s, true)
|
||||||
return strings.Join(result, "-")
|
return strings.Join(result, "-")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnakeCase covert string to snake_case
|
// SnakeCase covert string to snake_case
|
||||||
|
// non letters and numbers will be ignored
|
||||||
|
// eg. "Foo-#1😄$_%^&*(1bar" => "foo_1_1_bar"
|
||||||
func SnakeCase(s string) string {
|
func SnakeCase(s string) string {
|
||||||
if len(s) == 0 {
|
result := splitIntoStrings(s, false)
|
||||||
return ""
|
return strings.Join(result, "_")
|
||||||
}
|
|
||||||
|
|
||||||
regex := regexp.MustCompile(`[\W|_]+`)
|
|
||||||
blankSpace := " "
|
|
||||||
match := regex.ReplaceAllString(s, blankSpace)
|
|
||||||
rs := strings.Split(match, blankSpace)
|
|
||||||
|
|
||||||
var result []string
|
|
||||||
for _, v := range rs {
|
|
||||||
splitWords := splitWordsToLower(v)
|
|
||||||
if len(splitWords) > 0 {
|
|
||||||
result = append(result, splitWords...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpperSnakeCase covert string to upper SNAKE_CASE
|
||||||
|
// non letters and numbers will be ignored
|
||||||
|
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO_1_1_BAR"
|
||||||
|
func UpperSnakeCase(s string) string {
|
||||||
|
result := splitIntoStrings(s, true)
|
||||||
return strings.Join(result, "_")
|
return strings.Join(result, "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +1,100 @@
|
|||||||
package strutil
|
package strutil
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
// splitWordsToLower split a string into worlds by uppercase char
|
func splitIntoStrings(s string, upperCase bool) []string {
|
||||||
func splitWordsToLower(s string) []string {
|
var runes [][]rune
|
||||||
var result []string
|
lastCharType := 0
|
||||||
|
charType := 0
|
||||||
|
|
||||||
upperIndexes := upperIndex(s)
|
// split into fields based on type of unicode character
|
||||||
l := len(upperIndexes)
|
for _, r := range s {
|
||||||
if upperIndexes == nil || l == 0 {
|
switch true {
|
||||||
if s != "" {
|
case isLower(r):
|
||||||
result = append(result, s)
|
charType = 1
|
||||||
|
case isUpper(r):
|
||||||
|
charType = 2
|
||||||
|
case isDigit(r):
|
||||||
|
charType = 3
|
||||||
|
default:
|
||||||
|
charType = 4
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
if charType == lastCharType {
|
||||||
for i := 0; i < l; i++ {
|
runes[len(runes)-1] = append(runes[len(runes)-1], r)
|
||||||
if i < l-1 {
|
|
||||||
result = append(result, strings.ToLower(s[upperIndexes[i]:upperIndexes[i+1]]))
|
|
||||||
} else {
|
} else {
|
||||||
result = append(result, strings.ToLower(s[upperIndexes[i]:]))
|
runes = append(runes, []rune{r})
|
||||||
}
|
}
|
||||||
}
|
lastCharType = charType
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// upperIndex get a int slice which elements are all the uppercase char index of a string
|
for i := 0; i < len(runes)-1; i++ {
|
||||||
func upperIndex(s string) []int {
|
if isUpper(runes[i][0]) && isLower(runes[i+1][0]) {
|
||||||
var result []int
|
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
|
||||||
for i := 0; i < len(s); i++ {
|
runes[i] = runes[i][:len(runes[i])-1]
|
||||||
if 64 < s[i] && s[i] < 91 {
|
}
|
||||||
result = append(result, i)
|
}
|
||||||
|
|
||||||
|
// filter all none letters and none digit
|
||||||
|
var result []string
|
||||||
|
for _, rs := range runes {
|
||||||
|
if len(rs) > 0 && (unicode.IsLetter(rs[0]) || isDigit(rs[0])) {
|
||||||
|
if upperCase {
|
||||||
|
result = append(result, string(toUpperAll(rs)))
|
||||||
|
} else {
|
||||||
|
result = append(result, string(toLowerAll(rs)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(s) > 0 && result != nil && result[0] != 0 {
|
|
||||||
result = append([]int{0}, result...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isDigit checks if a character is digit ('0' to '9')
|
||||||
|
func isDigit(r rune) bool {
|
||||||
|
return r >= '0' && r <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
// isLower checks if a character is lower case ('a' to 'z')
|
||||||
|
func isLower(r rune) bool {
|
||||||
|
return r >= 'a' && r <= 'z'
|
||||||
|
}
|
||||||
|
|
||||||
|
// isUpper checks if a character is upper case ('A' to 'Z')
|
||||||
|
func isUpper(r rune) bool {
|
||||||
|
return r >= 'A' && r <= 'Z'
|
||||||
|
}
|
||||||
|
|
||||||
|
// toLower converts a character 'A' to 'Z' to its lower case
|
||||||
|
func toLower(r rune) rune {
|
||||||
|
if r >= 'A' && r <= 'Z' {
|
||||||
|
return r + 32
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// toLowerAll converts a character 'A' to 'Z' to its lower case
|
||||||
|
func toLowerAll(rs []rune) []rune {
|
||||||
|
for i := range rs {
|
||||||
|
rs[i] = toLower(rs[i])
|
||||||
|
}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// toUpper converts a character 'a' to 'z' to its upper case
|
||||||
|
func toUpper(r rune) rune {
|
||||||
|
if r >= 'a' && r <= 'z' {
|
||||||
|
return r - 32
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// toUpperAll converts a character 'a' to 'z' to its upper case
|
||||||
|
func toUpperAll(rs []rune) []rune {
|
||||||
|
for i := range rs {
|
||||||
|
rs[i] = toUpper(rs[i])
|
||||||
|
}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,67 +9,163 @@ import (
|
|||||||
func TestCamelCase(t *testing.T) {
|
func TestCamelCase(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCamelCase")
|
assert := internal.NewAssert(t, "TestCamelCase")
|
||||||
|
|
||||||
assert.Equal("fooBar", CamelCase("foo_bar"))
|
cases := map[string]string{
|
||||||
assert.Equal("fooBar", CamelCase("Foo-Bar"))
|
"": "",
|
||||||
assert.Equal("fooBar", CamelCase("Foo&bar"))
|
"foobar": "foobar",
|
||||||
assert.Equal("fooBar", CamelCase("foo bar"))
|
"&FOO:BAR$BAZ": "fooBarBaz",
|
||||||
|
"fooBar": "fooBar",
|
||||||
|
"FOObar": "foObar",
|
||||||
|
"$foo%": "foo",
|
||||||
|
" $#$Foo 22 bar ": "foo22Bar",
|
||||||
|
"Foo-#1😄$_%^&*(1bar": "foo11Bar",
|
||||||
|
}
|
||||||
|
|
||||||
assert.NotEqual("FooBar", CamelCase("foo_bar"))
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, CamelCase(k))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCapitalize(t *testing.T) {
|
func TestCapitalize(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCapitalize")
|
assert := internal.NewAssert(t, "TestCapitalize")
|
||||||
|
|
||||||
assert.Equal("Foo", Capitalize("foo"))
|
cases := map[string]string{
|
||||||
assert.Equal("Foo", Capitalize("Foo"))
|
"": "",
|
||||||
assert.Equal("Foo", Capitalize("Foo"))
|
"Foo": "Foo",
|
||||||
|
"_foo": "_foo",
|
||||||
|
"foobar": "Foobar",
|
||||||
|
"fooBar": "Foobar",
|
||||||
|
"foo Bar": "Foo bar",
|
||||||
|
"foo-bar": "Foo-bar",
|
||||||
|
"$foo%": "$foo%",
|
||||||
|
}
|
||||||
|
|
||||||
assert.NotEqual("foo", Capitalize("Foo"))
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, Capitalize(k))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKebabCase(t *testing.T) {
|
func TestKebabCase(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestKebabCase")
|
assert := internal.NewAssert(t, "TestKebabCase")
|
||||||
|
|
||||||
assert.Equal("foo-bar", KebabCase("Foo Bar-"))
|
cases := map[string]string{
|
||||||
assert.Equal("foo-bar", KebabCase("foo_Bar"))
|
"": "",
|
||||||
assert.Equal("foo-bar", KebabCase("fooBar"))
|
"foo-bar": "foo-bar",
|
||||||
assert.Equal("f-o-o-b-a-r", KebabCase("__FOO_BAR__"))
|
"--Foo---Bar-": "foo-bar",
|
||||||
|
"Foo Bar-": "foo-bar",
|
||||||
|
"foo_Bar": "foo-bar",
|
||||||
|
"fooBar": "foo-bar",
|
||||||
|
"FOOBAR": "foobar",
|
||||||
|
"FOO_BAR": "foo-bar",
|
||||||
|
"__FOO_BAR__": "foo-bar",
|
||||||
|
"$foo@Bar": "foo-bar",
|
||||||
|
" $#$Foo 22 bar ": "foo-22-bar",
|
||||||
|
"Foo-#1😄$_%^&*(1bar": "foo-1-1-bar",
|
||||||
|
}
|
||||||
|
|
||||||
assert.NotEqual("foo_bar", KebabCase("fooBar"))
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, KebabCase(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpperKebabCase(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestUpperKebabCase")
|
||||||
|
|
||||||
|
cases := map[string]string{
|
||||||
|
"": "",
|
||||||
|
"foo-bar": "FOO-BAR",
|
||||||
|
"--Foo---Bar-": "FOO-BAR",
|
||||||
|
"Foo Bar-": "FOO-BAR",
|
||||||
|
"foo_Bar": "FOO-BAR",
|
||||||
|
"fooBar": "FOO-BAR",
|
||||||
|
"FOOBAR": "FOOBAR",
|
||||||
|
"FOO_BAR": "FOO-BAR",
|
||||||
|
"__FOO_BAR__": "FOO-BAR",
|
||||||
|
"$foo@Bar": "FOO-BAR",
|
||||||
|
" $#$Foo 22 bar ": "FOO-22-BAR",
|
||||||
|
"Foo-#1😄$_%^&*(1bar": "FOO-1-1-BAR",
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, UpperKebabCase(k))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSnakeCase(t *testing.T) {
|
func TestSnakeCase(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestSnakeCase")
|
assert := internal.NewAssert(t, "TestSnakeCase")
|
||||||
|
|
||||||
assert.Equal("foo_bar", SnakeCase("Foo Bar-"))
|
cases := map[string]string{
|
||||||
assert.Equal("foo_bar", SnakeCase("foo_Bar"))
|
"": "",
|
||||||
assert.Equal("foo_bar", SnakeCase("fooBar"))
|
"foo-bar": "foo_bar",
|
||||||
assert.Equal("f_o_o_b_a_r", SnakeCase("__FOO_BAR__"))
|
"--Foo---Bar-": "foo_bar",
|
||||||
assert.Equal("a_bbc_s_a_b_b_c", SnakeCase("aBbc-s$@a&%_B.B^C"))
|
"Foo Bar-": "foo_bar",
|
||||||
|
"foo_Bar": "foo_bar",
|
||||||
|
"fooBar": "foo_bar",
|
||||||
|
"FOOBAR": "foobar",
|
||||||
|
"FOO_BAR": "foo_bar",
|
||||||
|
"__FOO_BAR__": "foo_bar",
|
||||||
|
"$foo@Bar": "foo_bar",
|
||||||
|
" $#$Foo 22 bar ": "foo_22_bar",
|
||||||
|
"Foo-#1😄$_%^&*(1bar": "foo_1_1_bar",
|
||||||
|
}
|
||||||
|
|
||||||
assert.NotEqual("foo-bar", SnakeCase("foo_Bar"))
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, SnakeCase(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpperSnakeCase(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestUpperSnakeCase")
|
||||||
|
|
||||||
|
cases := map[string]string{
|
||||||
|
"": "",
|
||||||
|
"foo-bar": "FOO_BAR",
|
||||||
|
"--Foo---Bar-": "FOO_BAR",
|
||||||
|
"Foo Bar-": "FOO_BAR",
|
||||||
|
"foo_Bar": "FOO_BAR",
|
||||||
|
"fooBar": "FOO_BAR",
|
||||||
|
"FOOBAR": "FOOBAR",
|
||||||
|
"FOO_BAR": "FOO_BAR",
|
||||||
|
"__FOO_BAR__": "FOO_BAR",
|
||||||
|
"$foo@Bar": "FOO_BAR",
|
||||||
|
" $#$Foo 22 bar ": "FOO_22_BAR",
|
||||||
|
"Foo-#1😄$_%^&*(1bar": "FOO_1_1_BAR",
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, UpperSnakeCase(k))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpperFirst(t *testing.T) {
|
func TestUpperFirst(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestLowerFirst")
|
assert := internal.NewAssert(t, "TestLowerFirst")
|
||||||
|
|
||||||
assert.Equal("Foo", UpperFirst("foo"))
|
cases := map[string]string{
|
||||||
assert.Equal("BAR", UpperFirst("bAR"))
|
"": "",
|
||||||
assert.Equal("FOo", UpperFirst("FOo"))
|
"foo": "Foo",
|
||||||
assert.Equal("FOo大", UpperFirst("fOo大"))
|
"bAR": "BAR",
|
||||||
|
"FOo": "FOo",
|
||||||
|
"fOo大": "FOo大",
|
||||||
|
}
|
||||||
|
|
||||||
assert.NotEqual("Bar", UpperFirst("BAR"))
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, UpperFirst(k))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLowerFirst(t *testing.T) {
|
func TestLowerFirst(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestLowerFirst")
|
assert := internal.NewAssert(t, "TestLowerFirst")
|
||||||
|
|
||||||
assert.Equal("foo", LowerFirst("foo"))
|
cases := map[string]string{
|
||||||
assert.Equal("bAR", LowerFirst("BAR"))
|
"": "",
|
||||||
assert.Equal("fOo", LowerFirst("FOo"))
|
"foo": "foo",
|
||||||
assert.Equal("fOo大", LowerFirst("FOo大"))
|
"bAR": "bAR",
|
||||||
|
"FOo": "fOo",
|
||||||
|
"fOo大": "fOo大",
|
||||||
|
}
|
||||||
|
|
||||||
assert.NotEqual("Bar", LowerFirst("BAR"))
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, LowerFirst(k))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPadEnd(t *testing.T) {
|
func TestPadEnd(t *testing.T) {
|
||||||
|
|||||||
50
system/os.go
50
system/os.go
@@ -9,6 +9,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsWindows check if current os is windows
|
// IsWindows check if current os is windows
|
||||||
@@ -50,27 +54,61 @@ func CompareOsEnv(key, comparedEnv string) bool {
|
|||||||
return env == comparedEnv
|
return env == comparedEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecCommand use shell /bin/bash -c to execute command
|
// ExecCommand execute command, return the stdout and stderr string of command, and error if error occur
|
||||||
|
// param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1
|
||||||
|
// in linux, use /bin/bash -c to execute command
|
||||||
|
// in windows, use powershell.exe to execute command
|
||||||
func ExecCommand(command string) (stdout, stderr string, err error) {
|
func ExecCommand(command string) (stdout, stderr string, err error) {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
var errout bytes.Buffer
|
var errOut bytes.Buffer
|
||||||
|
|
||||||
cmd := exec.Command("/bin/bash", "-c", command)
|
cmd := exec.Command("/bin/bash", "-c", command)
|
||||||
if IsWindows() {
|
if IsWindows() {
|
||||||
cmd = exec.Command("cmd")
|
cmd = exec.Command("powershell.exe", command)
|
||||||
}
|
}
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
cmd.Stderr = &errout
|
cmd.Stderr = &errOut
|
||||||
|
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stderr = string(errout.Bytes())
|
if utf8.Valid(errOut.Bytes()) {
|
||||||
|
stderr = byteToString(errOut.Bytes(), "UTF8")
|
||||||
|
} else if validator.IsGBK(errOut.Bytes()) {
|
||||||
|
stderr = byteToString(errOut.Bytes(), "GBK")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := out.Bytes()
|
||||||
|
if utf8.Valid(data) {
|
||||||
|
stdout = byteToString(data, "UTF8")
|
||||||
|
} else if validator.IsGBK(data) {
|
||||||
|
stdout = byteToString(data, "GBK")
|
||||||
}
|
}
|
||||||
stdout = string(out.Bytes())
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func byteToString(data []byte, charset string) string {
|
||||||
|
var result string
|
||||||
|
|
||||||
|
switch charset {
|
||||||
|
case "GBK":
|
||||||
|
decodeBytes, _ := simplifiedchinese.GBK.NewDecoder().Bytes(data)
|
||||||
|
result = string(decodeBytes)
|
||||||
|
case "GB18030":
|
||||||
|
decodeBytes, _ := simplifiedchinese.GB18030.NewDecoder().Bytes(data)
|
||||||
|
result = string(decodeBytes)
|
||||||
|
case "UTF8":
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
result = string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// GetOsBits get this system bits 32bit or 64bit
|
// GetOsBits get this system bits 32bit or 64bit
|
||||||
// return bit int (32/64)
|
// return bit int (32/64)
|
||||||
func GetOsBits() int {
|
func GetOsBits() int {
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ func TestOsDetection(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestOsJudgment")
|
assert := internal.NewAssert(t, "TestOsJudgment")
|
||||||
|
|
||||||
osType, _, _ := ExecCommand("echo $OSTYPE")
|
osType, _, _ := ExecCommand("echo $OSTYPE")
|
||||||
if strings.Index(osType, "linux") != -1 {
|
if strings.Contains(osType, "linux") {
|
||||||
assert.Equal(true, IsLinux())
|
assert.Equal(true, IsLinux())
|
||||||
}
|
}
|
||||||
if strings.Index(osType, "darwin") != -1 {
|
if strings.Contains(osType, "darwin") {
|
||||||
assert.Equal(true, IsMac())
|
assert.Equal(true, IsMac())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,9 @@ func TestOsEnvOperation(t *testing.T) {
|
|||||||
envNotExist := GetOsEnv("foo")
|
envNotExist := GetOsEnv("foo")
|
||||||
assert.Equal("", envNotExist)
|
assert.Equal("", envNotExist)
|
||||||
|
|
||||||
SetOsEnv("foo", "foo_value")
|
err := SetOsEnv("foo", "foo_value")
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
envExist := GetOsEnv("foo")
|
envExist := GetOsEnv("foo")
|
||||||
assert.Equal("foo_value", envExist)
|
assert.Equal("foo_value", envExist)
|
||||||
|
|
||||||
@@ -34,7 +36,7 @@ func TestOsEnvOperation(t *testing.T) {
|
|||||||
assert.Equal(false, CompareOsEnv("abc", "abc"))
|
assert.Equal(false, CompareOsEnv("abc", "abc"))
|
||||||
assert.Equal(false, CompareOsEnv("abc", "abc"))
|
assert.Equal(false, CompareOsEnv("abc", "abc"))
|
||||||
|
|
||||||
err := RemoveOsEnv("foo")
|
err = RemoveOsEnv("foo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
@@ -44,22 +46,27 @@ func TestOsEnvOperation(t *testing.T) {
|
|||||||
func TestExecCommand(t *testing.T) {
|
func TestExecCommand(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestExecCommand")
|
assert := internal.NewAssert(t, "TestExecCommand")
|
||||||
|
|
||||||
out, errout, err := ExecCommand("ls")
|
// linux or mac
|
||||||
t.Log("std out: ", out)
|
stdout, stderr, err := ExecCommand("ls")
|
||||||
t.Log("std err: ", errout)
|
t.Log("std out: ", stdout)
|
||||||
|
t.Log("std err: ", stderr)
|
||||||
|
assert.Equal("", stderr)
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
|
|
||||||
out, errout, err = ExecCommand("abc")
|
// windows
|
||||||
t.Log("std out: ", out)
|
stdout, stderr, err = ExecCommand("dir")
|
||||||
t.Log("std err: ", errout)
|
t.Log("std out: ", stdout)
|
||||||
if err != nil {
|
t.Log("std err: ", stderr)
|
||||||
t.Logf("error: %v\n", err)
|
if IsWindows() {
|
||||||
|
assert.IsNil(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !IsWindows() {
|
// error command
|
||||||
|
stdout, stderr, err = ExecCommand("abc")
|
||||||
|
t.Log("std out: ", stdout)
|
||||||
|
t.Log("std err: ", stderr)
|
||||||
assert.IsNotNil(err)
|
assert.IsNotNil(err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetOsBits(t *testing.T) {
|
func TestGetOsBits(t *testing.T) {
|
||||||
osBits := GetOsBits()
|
osBits := GetOsBits()
|
||||||
|
|||||||
@@ -15,11 +15,24 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
var isAlphaRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
|
var (
|
||||||
|
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
|
||||||
|
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
|
||||||
|
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
|
||||||
|
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
|
||||||
|
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
|
||||||
|
emailMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
|
||||||
|
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
|
||||||
|
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
|
||||||
|
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
|
||||||
|
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
|
||||||
|
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
|
||||||
|
base64Matcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
|
||||||
|
)
|
||||||
|
|
||||||
// IsAlpha checks if the string contains only letters (a-zA-Z)
|
// IsAlpha checks if the string contains only letters (a-zA-Z)
|
||||||
func IsAlpha(str string) bool {
|
func IsAlpha(str string) bool {
|
||||||
return isAlphaRegexMatcher.MatchString(str)
|
return alphaMatcher.MatchString(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAllUpper check if the string is all upper case letters A-Z
|
// IsAllUpper check if the string is all upper case letters A-Z
|
||||||
@@ -62,11 +75,9 @@ func ContainLower(str string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var containLetterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
|
|
||||||
|
|
||||||
// ContainLetter check if the string contain at least one letter
|
// ContainLetter check if the string contain at least one letter
|
||||||
func ContainLetter(str string) bool {
|
func ContainLetter(str string) bool {
|
||||||
return containLetterRegexMatcher.MatchString(str)
|
return letterRegexMatcher.MatchString(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsJSON checks if the string is valid JSON
|
// IsJSON checks if the string is valid JSON
|
||||||
@@ -86,11 +97,9 @@ func IsFloatStr(str string) bool {
|
|||||||
return e == nil
|
return e == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var isIntStrRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
|
|
||||||
|
|
||||||
// IsIntStr check if the string can convert to a integer.
|
// IsIntStr check if the string can convert to a integer.
|
||||||
func IsIntStr(str string) bool {
|
func IsIntStr(str string) bool {
|
||||||
return isIntStrRegexMatcher.MatchString(str)
|
return intStrMatcher.MatchString(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsIp check if the string is a ip address.
|
// IsIp check if the string is a ip address.
|
||||||
@@ -125,8 +134,6 @@ func IsPort(str string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var isUrlRegexMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
|
|
||||||
|
|
||||||
// IsUrl check if the string is url.
|
// IsUrl check if the string is url.
|
||||||
func IsUrl(str string) bool {
|
func IsUrl(str string) bool {
|
||||||
if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
|
if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
|
||||||
@@ -143,64 +150,48 @@ func IsUrl(str string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return isUrlRegexMatcher.MatchString(str)
|
return urlMatcher.MatchString(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isDnsRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
|
|
||||||
|
|
||||||
// IsDns check if the string is dns.
|
// IsDns check if the string is dns.
|
||||||
func IsDns(dns string) bool {
|
func IsDns(dns string) bool {
|
||||||
return isDnsRegexMatcher.MatchString(dns)
|
return dnsMatcher.MatchString(dns)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isEmailRegexMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
|
|
||||||
|
|
||||||
// IsEmail check if the string is a email address.
|
// IsEmail check if the string is a email address.
|
||||||
func IsEmail(email string) bool {
|
func IsEmail(email string) bool {
|
||||||
return isEmailRegexMatcher.MatchString(email)
|
return emailMatcher.MatchString(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isChineseMobileRegexMatcher *regexp.Regexp = regexp.MustCompile("^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$")
|
|
||||||
|
|
||||||
// IsChineseMobile check if the string is chinese mobile number.
|
// IsChineseMobile check if the string is chinese mobile number.
|
||||||
func IsChineseMobile(mobileNum string) bool {
|
func IsChineseMobile(mobileNum string) bool {
|
||||||
return isChineseMobileRegexMatcher.MatchString(mobileNum)
|
return chineseMobileMatcher.MatchString(mobileNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isChineseIdNumRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
|
|
||||||
|
|
||||||
// IsChineseIdNum check if the string is chinese id number.
|
// IsChineseIdNum check if the string is chinese id number.
|
||||||
func IsChineseIdNum(id string) bool {
|
func IsChineseIdNum(id string) bool {
|
||||||
return isChineseIdNumRegexMatcher.MatchString(id)
|
return chineseIdMatcher.MatchString(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
var containChineseRegexMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
|
|
||||||
|
|
||||||
// ContainChinese check if the string contain mandarin chinese.
|
// ContainChinese check if the string contain mandarin chinese.
|
||||||
func ContainChinese(s string) bool {
|
func ContainChinese(s string) bool {
|
||||||
return containChineseRegexMatcher.MatchString(s)
|
return chineseMatcher.MatchString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isChinesePhoneRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
|
|
||||||
|
|
||||||
// IsChinesePhone check if the string is chinese phone number.
|
// IsChinesePhone check if the string is chinese phone number.
|
||||||
// Valid chinese phone is xxx-xxxxxxxx or xxxx-xxxxxxx
|
// Valid chinese phone is xxx-xxxxxxxx or xxxx-xxxxxxx
|
||||||
func IsChinesePhone(phone string) bool {
|
func IsChinesePhone(phone string) bool {
|
||||||
return isChinesePhoneRegexMatcher.MatchString(phone)
|
return chinesePhoneMatcher.MatchString(phone)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isCreditCardRegexMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
|
|
||||||
|
|
||||||
// IsCreditCard check if the string is credit card.
|
// IsCreditCard check if the string is credit card.
|
||||||
func IsCreditCard(creditCart string) bool {
|
func IsCreditCard(creditCart string) bool {
|
||||||
return isCreditCardRegexMatcher.MatchString(creditCart)
|
return creditCardMatcher.MatchString(creditCart)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isBase64RegexMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
|
|
||||||
|
|
||||||
// IsBase64 check if the string is base64 string.
|
// IsBase64 check if the string is base64 string.
|
||||||
func IsBase64(base64 string) bool {
|
func IsBase64(base64 string) bool {
|
||||||
return isBase64RegexMatcher.MatchString(base64)
|
return base64Matcher.MatchString(base64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmptyString check if the string is empty.
|
// IsEmptyString check if the string is empty.
|
||||||
@@ -283,3 +274,40 @@ func IsZeroValue(value any) bool {
|
|||||||
|
|
||||||
return reflect.DeepEqual(rv.Interface(), reflect.Zero(rv.Type()).Interface())
|
return reflect.DeepEqual(rv.Interface(), reflect.Zero(rv.Type()).Interface())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsGBK check if data encoding is gbk
|
||||||
|
// Note: this function is implemented by whether double bytes fall within the encoding range of gbk,
|
||||||
|
// while each byte of utf-8 encoding format falls within the encoding range of gbk.
|
||||||
|
// Therefore, utf8.valid() should be called first to check whether it is not utf-8 encoding,
|
||||||
|
// and then call IsGBK() to check gbk encoding. like below
|
||||||
|
/**
|
||||||
|
data := []byte("你好")
|
||||||
|
if utf8.Valid(data) {
|
||||||
|
fmt.Println("data encoding is utf-8")
|
||||||
|
}else if(IsGBK(data)) {
|
||||||
|
fmt.Println("data encoding is GBK")
|
||||||
|
}
|
||||||
|
fmt.Println("data encoding is unknown")
|
||||||
|
**/
|
||||||
|
func IsGBK(data []byte) bool {
|
||||||
|
i := 0
|
||||||
|
for i < len(data) {
|
||||||
|
if data[i] <= 0xff {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
if data[i] >= 0x81 &&
|
||||||
|
data[i] <= 0xfe &&
|
||||||
|
data[i+1] >= 0x40 &&
|
||||||
|
data[i+1] <= 0xfe &&
|
||||||
|
data[i+1] != 0xf7 {
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsAllUpper(t *testing.T) {
|
func TestIsAllUpper(t *testing.T) {
|
||||||
@@ -388,3 +390,13 @@ func TestIsZeroValue(t *testing.T) {
|
|||||||
assert.Equal(false, IsZeroValue(value))
|
assert.Equal(false, IsZeroValue(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsGBK(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsGBK")
|
||||||
|
|
||||||
|
str := "你好"
|
||||||
|
gbkData, _ := simplifiedchinese.GBK.NewEncoder().Bytes([]byte(str))
|
||||||
|
|
||||||
|
assert.Equal(true, IsGBK(gbkData))
|
||||||
|
assert.Equal(false, utf8.Valid(gbkData))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user