mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-08 22:52: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
|
current := dl.Head
|
||||||
|
dl.Head = current.Next
|
||||||
|
dl.Head.Pre = nil
|
||||||
|
dl.length--
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtTail delete value in doubly linklist at tail index
|
// DeleteAtTail delete value in doubly linklist at tail
|
||||||
func (link *DoublyLink[T]) DeleteAtTail() error {
|
func (dl *DoublyLink[T]) DeleteAtTail() {
|
||||||
if link.Head == nil {
|
if dl.Head == nil {
|
||||||
return errors.New("doubly link list no exist")
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
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
|
current := sl.Head
|
||||||
|
sl.Head = current.Next
|
||||||
|
sl.length--
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtTail delete value in singly linklist at tail index
|
// DeleteAtTail delete value in singly linklist at tail
|
||||||
func (link *SinglyLink[T]) DeleteAtTail() error {
|
func (sl *SinglyLink[T]) DeleteAtTail() {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return errors.New("singly link list no exist")
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
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}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -132,12 +132,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||||
|
|
||||||
<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)
|
||||||
@@ -228,12 +230,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||||
|
|
||||||
<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}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -628,12 +627,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||||
|
|
||||||
<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)
|
||||||
@@ -724,12 +725,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||||
|
|
||||||
<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,10 +84,8 @@ func Debounced(fn func(), duration time.Duration) func() {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
<-timer.C
|
||||||
case <-timer.C:
|
go fn()
|
||||||
go fn()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
@@ -113,7 +120,7 @@ func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(inde
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
//DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal).
|
// DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal).
|
||||||
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1, item2 T) bool) []T {
|
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1, item2 T) bool) []T {
|
||||||
result := make([]T, 0)
|
result := make([]T, 0)
|
||||||
|
|
||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(s) > 0 && result != nil && result[0] != 0 {
|
|
||||||
result = append([]int{0}, result...)
|
// 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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,21 +46,26 @@ 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
|
||||||
assert.IsNotNil(err)
|
stdout, stderr, err = ExecCommand("abc")
|
||||||
}
|
t.Log("std out: ", stdout)
|
||||||
|
t.Log("std err: ", stderr)
|
||||||
|
assert.IsNotNil(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOsBits(t *testing.T) {
|
func TestGetOsBits(t *testing.T) {
|
||||||
|
|||||||
@@ -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