1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-23 13:52:26 +08:00

Compare commits

..

8 Commits

Author SHA1 Message Date
dudaodong
d7f23e2dee Merge branch 'main' into v2 2023-11-22 17:20:17 +08:00
o98k
3802c715c3 [feature]<slice>: support random item (#146)
Signed-off-by: o98k-ok <hggend@gmail.com>
2023-11-22 16:51:37 +08:00
dudaodong
4b12173f24 Merge branch 'main' into v2 2023-11-16 15:28:34 +08:00
guangwu
31c618c187 chore: use bytes.Equal instead (#144) 2023-11-16 15:26:20 +08:00
dudaodong
6497b321b0 refactor: clean code 2023-10-30 17:55:18 +08:00
dudaodong
bda78201f5 doc: update readme file 2023-10-28 17:02:24 +08:00
dudaodong
0753ea2801 feat: add context for httpClient SendRequest function 2023-10-18 19:13:34 +08:00
dudaodong
e25b53712b doc: add play ground demo 2023-10-08 11:19:44 +08:00
19 changed files with 190 additions and 61 deletions

View File

@@ -21,7 +21,7 @@
## <a href="https://www.golancet.cn/en/" target="_blank"> Website</a> | [简体中文](./README_zh-CN.md)
## Feature
## Features
- 👏 Comprehensive, efficient and reusable.
- 💪 600+ go util functions, support string, slice, datetime, net, crypt...
@@ -453,10 +453,14 @@ import "github.com/duke-git/lancet/v2/cryptor"
[[play](https://go.dev/play/p/uef0q1fz53I)]
- **<big>GenerateRsaKeyPair</big>** : creates rsa private and public key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#GenerateRsaKeyPair)]
[[play](https://go.dev/play/p/sSVmkfENKMz)]
- **<big>RsaEncryptOAEP</big>** : encrypts the given data with RSA-OAEP.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaEncryptOAEP)]
[[play](https://go.dev/play/p/sSVmkfENKMz)]
- **<big>RsaDecryptOAEP</big>** : decrypts the data with RSA-OAEP
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaDecryptOAEP)]
[[play](https://go.dev/play/p/sSVmkfENKMz)]
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
@@ -1553,6 +1557,7 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/6zXRH_c0Qd3)]
- **<big>IsNotBlank</big>** : checks if a string is not whitespace or not empty.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#IsNotBlank)]
[[play](https://go.dev/play/p/e_oJW0RAquA)]
- **<big>HasPrefixAny</big>** : checks if a string starts with any of an array of specified strings.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#HasPrefixAny)]
[[play](https://go.dev/play/p/8UUTl2C5slo)]

View File

@@ -453,10 +453,14 @@ import "github.com/duke-git/lancet/v2/cryptor"
[[play](https://go.dev/play/p/uef0q1fz53I)]
- **<big>GenerateRsaKeyPair</big>** : 创建rsa公钥私钥和key。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#GenerateRsaKeyPair)]
[[play](https://go.dev/play/p/sSVmkfENKMz)]
- **<big>RsaEncryptOAEP</big>** : rsa OAEP加密。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaEncryptOAEP)]
[[play](https://go.dev/play/p/sSVmkfENKMz)]
- **<big>RsaDecryptOAEP</big>** : rsa OAEP解密。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaDecryptOAEP)]
[[play](https://go.dev/play/p/sSVmkfENKMz)]
<h3 id="datetime"> 7. datetime 日期时间处理包,格式化日期,比较日期。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -1560,6 +1564,7 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/6zXRH_c0Qd3)]
- **<big>IsNotBlank</big>** : 检查字符串是否不为空。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#IsNotBlank)]
[[play](https://go.dev/play/p/e_oJW0RAquA)]
- **<big>HasPrefixAny</big>** : 检查字符串是否以指定字符串数组中的任何一个开头。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#HasPrefixAny)]
[[play](https://go.dev/play/p/8UUTl2C5slo)]

View File

@@ -70,7 +70,7 @@ func compareRefValue(operator string, leftObj, rightObj any, kind reflect.Kind)
switch operator {
case equal:
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
if bytes.Equal(bytesObj1, bytesObj2) {
return true
}
case lessThan:

View File

@@ -508,14 +508,14 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
}
// GenerateRsaKeyPair create rsa private and public key.
// Play: todo
// Play: https://go.dev/play/p/sSVmkfENKMz
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey) {
privateKey, _ := rsa.GenerateKey(rand.Reader, keySize)
return privateKey, &privateKey.PublicKey
}
// RsaEncryptOAEP encrypts the given data with RSA-OAEP.
// Play: todo
// Play: https://go.dev/play/p/sSVmkfENKMz
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error) {
encryptedBytes, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &key, data, label)
if err != nil {
@@ -526,7 +526,7 @@ func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error
}
// RsaDecryptOAEP decrypts the data with RSA-OAEP.
// Play: todo
// Play: https://go.dev/play/p/sSVmkfENKMz
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error) {
decryptedBytes, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, &key, ciphertext, label)
if err != nil {

View File

@@ -1437,7 +1437,7 @@ func main() {
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey)
```
<b>示例:></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sSVmkfENKMz)</span></b>
```go
package main
@@ -1462,7 +1462,7 @@ func main() {
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error)
```
<b>示例:></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sSVmkfENKMz)</span></b>
```go
package main
@@ -1505,7 +1505,7 @@ func main() {
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error)
```
<b>示例:></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sSVmkfENKMz)</span></b>
```go
package main

View File

@@ -843,7 +843,7 @@ func main() {
### <span id="ReadFile">ReadFile</span>
<p>读取文件或者URL</p>
<p>读取文件或者URL</p>
<b>函数签名:</b>
@@ -851,7 +851,7 @@ func main() {
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
```
<b>示例:<span style="float:right;display:inline-block;"></span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uNep3Tr8fqF)</span></b>
```go
package main
@@ -862,19 +862,19 @@ import (
)
func main() {
reader, fn, err := ReadFile("https://httpbin.org/robots.txt")
if err != nil {
return
}
defer fn()
reader, fn, err := fileutil.ReadFile("https://httpbin.org/robots.txt")
if err != nil {
return
}
defer fn()
dat, err := io.ReadAll(reader)
if err != nil {
return
}
fmt.Println(string(dat))
// Output:
// User-agent: *
// Disallow: /deny
dat, err := io.ReadAll(reader)
if err != nil {
return
}
fmt.Println(string(dat))
// Output:
// User-agent: *
// Disallow: /deny
}
```

View File

@@ -2488,4 +2488,35 @@ func main() {
// [[2 4] [1 3 5]]
// [[1 2] [3 4] [5]]
}
```
### <span id="Random">Random</span>
<p>随机返回切片中元素以及下标, 当切片长度为0时返回下标-1</p>
<b>函数签名:</b>
```go
func Random[T any](slice []T) (val T, idx int)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](TODO)</span></b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
val, idx := slice.Random(nums)
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
}
```

View File

@@ -1080,13 +1080,13 @@ func main() {
<p>Checks if a string is not whitespace or not empty.</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func IsNotBlank(str string) bool
```
<b>Example:</b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/e_oJW0RAquA)</span></b>
```go
import (
@@ -1095,11 +1095,11 @@ import (
)
func main() {
result1 := IsNotBlank("")
result2 := IsNotBlank(" ")
result3 := IsNotBlank("\t\v\f\n")
result4 := IsNotBlank(" 中文")
result5 := IsNotBlank(" world ")
result1 := strutil.IsNotBlank("")
result2 := strutil.IsNotBlank(" ")
result3 := strutil.IsNotBlank("\t\v\f\n")
result4 := strutil.IsNotBlank(" 中文")
result5 := strutil.IsNotBlank(" world ")
fmt.Println(result1)
fmt.Println(result2)

View File

@@ -1437,7 +1437,7 @@ func main() {
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey)
```
<b>Example:></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/sSVmkfENKMz)</span></b>
```go
package main
@@ -1462,7 +1462,7 @@ func main() {
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error)
```
<b>Example:></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/sSVmkfENKMz)</span></b>
```go
package main
@@ -1505,7 +1505,7 @@ func main() {
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error)
```
<b>Example:></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/sSVmkfENKMz)</span></b>
```go
package main

View File

@@ -843,7 +843,7 @@ func main() {
### <span id="ReadFile">ReadFile</span>
<p>Read File/URL</p>
<p>Read File or URL.</p>
<b>Signature:</b>
@@ -851,7 +851,7 @@ func main() {
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
```
<b>Example:<span style="float:right;display:inline-block;"> </span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uNep3Tr8fqF)</span></b>
```go
package main
@@ -862,19 +862,19 @@ import (
)
func main() {
reader, fn, err := ReadFile("https://httpbin.org/robots.txt")
if err != nil {
return
}
defer fn()
reader, fn, err := fileutil.ReadFile("https://httpbin.org/robots.txt")
if err != nil {
return
}
defer fn()
dat, err := io.ReadAll(reader)
if err != nil {
return
}
fmt.Println(string(dat))
// Output:
// User-agent: *
// Disallow: /deny
dat, err := io.ReadAll(reader)
if err != nil {
return
}
fmt.Println(string(dat))
// Output:
// User-agent: *
// Disallow: /deny
}
```

View File

@@ -2486,4 +2486,34 @@ func main() {
// [[2 4] [1 3 5]]
// [[1 2] [3 4] [5]]
}
```
### <span id="Random">Random</span>
<p>Random get a random item of slice, return idx=-1 when slice is empty. </p>
<b>Signature:</b>
```go
func Random[T any](slice []T) (val T, idx int)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](TODO)</span></b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
val, idx := slice.Random(nums)
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
}
```

View File

@@ -1087,7 +1087,7 @@ func main() {
func IsNotBlank(str string) bool
```
<b>Example:</b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/e_oJW0RAquA)</span></b>
```go
import (
@@ -1096,11 +1096,11 @@ import (
)
func main() {
result1 := IsNotBlank("")
result2 := IsNotBlank(" ")
result3 := IsNotBlank("\t\v\f\n")
result4 := IsNotBlank(" 中文")
result5 := IsNotBlank(" world ")
result1 := strutil.IsNotBlank("")
result2 := strutil.IsNotBlank(" ")
result3 := strutil.IsNotBlank("\t\v\f\n")
result4 := strutil.IsNotBlank(" 中文")
result5 := strutil.IsNotBlank(" world ")
fmt.Println(result1)
fmt.Println(result2)

View File

@@ -627,7 +627,7 @@ func WriteBytesToFile(filepath string, content []byte) error {
}
// ReadFile get file reader by a url or a local file
// Play: todo
// Play: https://go.dev/play/p/uNep3Tr8fqF
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) {
switch {
case validator.IsUrl(path):

View File

@@ -14,6 +14,7 @@ package netutil
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"errors"
@@ -110,22 +111,23 @@ type HttpClientConfig struct {
Verbose bool
}
// defaultHttpClientConfig defalut client config
// defaultHttpClientConfig defalut client config.
var defaultHttpClientConfig = &HttpClientConfig{
Compressed: false,
HandshakeTimeout: 20 * time.Second,
ResponseTimeout: 40 * time.Second,
}
// HttpClient is used for sending http request
// HttpClient is used for sending http request.
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
Context context.Context
}
// NewHttpClient make a HttpClient instance
// NewHttpClient make a HttpClient instance.
func NewHttpClient() *HttpClient {
client := &HttpClient{
Client: &http.Client{
@@ -141,7 +143,7 @@ func NewHttpClient() *HttpClient {
return client
}
// NewHttpClientWithConfig make a HttpClient instance with pass config
// NewHttpClientWithConfig make a HttpClient instance with pass config.
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient {
if config == nil {
config = defaultHttpClientConfig
@@ -176,6 +178,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
rawUrl := request.RawURL
req, err := http.NewRequest(request.Method, rawUrl, bytes.NewBuffer(request.Body))
if client.Context != nil {
req, err = http.NewRequestWithContext(client.Context, request.Method, rawUrl, bytes.NewBuffer(request.Body))
}
if err != nil {
return nil, err
}

View File

@@ -12,6 +12,7 @@ import (
"strings"
"time"
"github.com/duke-git/lancet/v2/random"
"golang.org/x/exp/constraints"
)
@@ -1229,3 +1230,14 @@ func Partition[T any](slice []T, predicates ...func(item T) bool) [][]T {
return result
}
// Random get a random item of slice, return idx=-1 when slice is empty
// Play: todo
func Random[T any](slice []T) (val T, idx int) {
if len(slice) == 0 {
return val, -1
}
idx = random.RandInt(0, len(slice))
return slice[idx], idx
}

View File

@@ -1063,3 +1063,14 @@ func ExamplePartition() {
// [[2 4] [1 3 5]]
// [[1 2] [3 4] [5]]
}
func ExampleRandom() {
nums := []int{1, 2, 3, 4, 5}
val, idx := Random(nums)
if idx >= 0 && idx < len(nums) && Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
}

View File

@@ -1185,3 +1185,28 @@ func TestPartition(t *testing.T) {
assert.Equal([][]int{{2, 4}, {1, 3, 5}}, Partition([]int{1, 2, 3, 4, 5}, func(n int) bool { return n%2 == 0 }))
assert.Equal([][]int{{1, 2}, {3, 4}, {5}}, Partition([]int{1, 2, 3, 4, 5}, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 }))
}
func TestRandom(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRandom")
var arr []int
var val, idx int
_, idx = Random(arr)
assert.Equal(-1, idx)
arr = []int{}
_, idx = Random(arr)
assert.Equal(-1, idx)
arr = []int{1}
val, idx = Random(arr)
assert.Equal(0, idx)
assert.Equal(arr[idx], val)
arr = []int{1, 2, 3}
val, idx = Random(arr)
assert.Greater(len(arr), idx)
assert.Equal(arr[idx], val)
}

View File

@@ -409,6 +409,7 @@ func IsBlank(str string) bool {
}
// IsNotBlank checks if a string is not whitespace, not empty.
// Play: https://go.dev/play/p/e_oJW0RAquA
func IsNotBlank(str string) bool {
return !IsBlank(str)
}

View File

@@ -32,8 +32,10 @@ func splitIntoStrings(s string, upperCase bool) []string {
for i := 0; i < len(runes)-1; i++ {
if isUpper(runes[i][0]) && isLower(runes[i+1][0]) {
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
runes[i] = runes[i][:len(runes[i])-1]
length := len(runes[i]) - 1
temp := runes[i][length]
runes[i+1] = append([]rune{temp}, runes[i+1]...)
runes[i] = runes[i][:length]
}
}