mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-06 21:52:28 +08:00
Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76b82a2fa1 | ||
|
|
d9dc2993b3 | ||
|
|
ae42a9fdff | ||
|
|
f37e55d9f1 | ||
|
|
d920a51988 | ||
|
|
561c42a24e | ||
|
|
12d74489d5 | ||
|
|
4959f26003 | ||
|
|
eb683a33d2 | ||
|
|
0e63489e9e | ||
|
|
d9e318550a | ||
|
|
993b0e6023 | ||
|
|
7cf358a0ec | ||
|
|
b85545c584 | ||
|
|
c3c6c92cd4 | ||
|
|
8587abc977 | ||
|
|
5c01b7e675 | ||
|
|
0247ac232a | ||
|
|
e77354d7ff | ||
|
|
8998dc35bb | ||
|
|
ad9fd196ce | ||
|
|
c8a65c33a4 | ||
|
|
69a797f8ed | ||
|
|
1e5b69e9bf | ||
|
|
275abcc8c2 | ||
|
|
065b3b84fe | ||
|
|
4bc43f3278 | ||
|
|
f3382ceac9 | ||
|
|
d20f8783b2 | ||
|
|
8432a4e1ee | ||
|
|
5a8ff17b52 | ||
|
|
6b46a0c05c | ||
|
|
4b8b624b4c | ||
|
|
f274375e62 | ||
|
|
6dc017a5fa | ||
|
|
e1fb97095d | ||
|
|
d8f5a15590 | ||
|
|
1202ac955d | ||
|
|
84b2cec9b5 | ||
|
|
2d01a13787 | ||
|
|
db9b045500 | ||
|
|
2701bcc4d2 | ||
|
|
b9745fd08b | ||
|
|
3b1597d6f7 | ||
|
|
40ab5e8f7b | ||
|
|
cacedf2a05 | ||
|
|
4fc391895b | ||
|
|
b419319e66 | ||
|
|
db34b5f69c | ||
|
|
ee44526d9e | ||
|
|
6576b1f0cb | ||
|
|
93108bafb9 | ||
|
|
07f5e0697f | ||
|
|
4ba91d7e4c | ||
|
|
ab81d9c283 | ||
|
|
a74038466f | ||
|
|
02daa7f6cb | ||
|
|
fef6fd7b9d | ||
|
|
f6cd98086f | ||
|
|
24eb2bbacd | ||
|
|
15c1537bf0 | ||
|
|
c02654559a | ||
|
|
634ca09e8c | ||
|
|
f2e743dcf4 | ||
|
|
f8f58cae10 | ||
|
|
215b79140d | ||
|
|
0bd675340f | ||
|
|
f3d73899b1 | ||
|
|
d4a20b239a | ||
|
|
4c28431451 | ||
|
|
168ed096c7 | ||
|
|
a060769635 | ||
|
|
0a99492cf6 | ||
|
|
fb3de03f37 | ||
|
|
43c2fd2a22 | ||
|
|
279d0754ba | ||
|
|
f133b32faa | ||
|
|
b98d5edbb5 | ||
|
|
9e39c31087 | ||
|
|
26bc40c614 | ||
|
|
76d68e326b | ||
|
|
67b4782ac2 | ||
|
|
1d8b9a2625 | ||
|
|
94ae1acc78 | ||
|
|
aece2995d6 | ||
|
|
f5ec5eb58d | ||
|
|
d62284e9a6 | ||
|
|
b6815224fd | ||
|
|
5931b882ee | ||
|
|
f8096e3585 | ||
|
|
979381bfb7 | ||
|
|
3e2c25f827 | ||
|
|
2c7bcc9fbb | ||
|
|
3a944ab12f | ||
|
|
387079d034 | ||
|
|
33e3631b72 | ||
|
|
b3149ea619 | ||
|
|
116ff284c3 | ||
|
|
0cb251f7b8 | ||
|
|
683def2242 | ||
|
|
d4a90f2869 | ||
|
|
be67de3b40 | ||
|
|
6898ed413e | ||
|
|
5dbdbcd651 | ||
|
|
ae0facd32d | ||
|
|
2d7e19fb87 | ||
|
|
24d4a03227 | ||
|
|
93fb089f6e | ||
|
|
2fe272f2ef | ||
|
|
77859ffa15 | ||
|
|
f83f47df3a | ||
|
|
885c08847d | ||
|
|
cc4a20751f | ||
|
|
b0d1d39452 | ||
|
|
02fa7bc8be | ||
|
|
433eb63b86 | ||
|
|
a2541dac03 | ||
|
|
690e746811 | ||
|
|
7cb97a26c5 | ||
|
|
39d373d37b | ||
|
|
1aefd6aa12 | ||
|
|
c7aa44b8a4 | ||
|
|
0e3dc68de5 | ||
|
|
4083e75ed4 | ||
|
|
1327eff62f | ||
|
|
eb24c37143 | ||
|
|
b7a6c91064 | ||
|
|
555e185871 | ||
|
|
cb0efc5cc7 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -5,5 +5,9 @@ cryptor/*.txt
|
|||||||
fileutil/*.txt
|
fileutil/*.txt
|
||||||
fileutil/*.zip
|
fileutil/*.zip
|
||||||
fileutil/*.link
|
fileutil/*.link
|
||||||
|
fileutil/tempdir
|
||||||
fileutil/unzip/*
|
fileutil/unzip/*
|
||||||
cryptor/*.pem
|
slice/testdata/*
|
||||||
|
cryptor/*.pem
|
||||||
|
docs/node_modules
|
||||||
|
docs/.vitepress
|
||||||
602
README.md
602
README.md
@@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
<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)
|
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
[](https://codecov.io/gh/duke-git/lancet)
|
[](https://codecov.io/gh/duke-git/lancet)
|
||||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
[](https://github.com/duke-git/lancet/blob/v1/LICENSE)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -23,10 +23,10 @@ English | [简体中文](./README_zh-CN.md)
|
|||||||
|
|
||||||
## Feature
|
## Feature
|
||||||
|
|
||||||
- 👏 Comprehensive, efficient and reusable.
|
- 👏 Comprehensive, efficient and reusable.
|
||||||
- 💪 180+ go util functions, support string, slice, datetime, net, crypt...
|
- 💪 400+ go util functions, support string, slice, datetime, net, crypt...
|
||||||
- 💅 Only depend on the go standard library.
|
- 💅 Only depend on the go standard library.
|
||||||
- 🌍 Unit test for every exported function.
|
- 🌍 Unit test for every exported function.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ import "github.com/duke-git/lancet/strutil"
|
|||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Here takes the string function ReverseStr (reverse order string) as an example, and the strutil package needs to be imported.
|
Here takes the string function Reverse (reverse order string) as an example, and the strutil package needs to be imported.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -56,99 +56,157 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := "hello"
|
s := "hello"
|
||||||
rs := strutil.ReverseStr(s)
|
rs := strutil.Reverse(s)
|
||||||
fmt.Println(rs) //olleh
|
fmt.Println(rs) //olleh
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
### Convertor package contains some functions for data convertion.
|
|
||||||
|
### 1. Compare package provides a lightweight comparison function on any type.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/duke-git/lancet/compare"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Function list:
|
||||||
|
|
||||||
|
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#Equal)
|
||||||
|
- [EqualValue](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#EqualValue)
|
||||||
|
- [LessThan](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#LessThan)
|
||||||
|
- [GreaterThan](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#GreaterThan)
|
||||||
|
- [LessOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#LessOrEqual)
|
||||||
|
- [GreaterOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#GreaterOrEqual)
|
||||||
|
|
||||||
|
### 2. Convertor package contains some functions for data convertion.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/convertor"
|
import "github.com/duke-git/lancet/convertor"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorHexToRGB)
|
|
||||||
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorRGBToHex)
|
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ColorHexToRGB)
|
||||||
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)
|
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ColorRGBToHex)
|
||||||
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)
|
- [ToBool](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToBool)
|
||||||
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)
|
- [ToBytes](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToBytes)
|
||||||
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)
|
- [ToChar](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToChar)
|
||||||
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)
|
- [ToChannel](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToChannel)
|
||||||
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)
|
- [ToInt](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToInt)
|
||||||
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)
|
- [ToJson](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToJson)
|
||||||
|
- [ToString](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToString)
|
||||||
### Cryptor package is for data encryption and decryption.
|
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#StructToMap)
|
||||||
|
- [EncodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#EncodeByte)
|
||||||
|
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DecodeByte)
|
||||||
|
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DeepClone)
|
||||||
|
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#CopyProperties)
|
||||||
|
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToInterface)
|
||||||
|
- [Utf8ToGbk](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#Utf8ToGbk)
|
||||||
|
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#GbkToUtf8)
|
||||||
|
|
||||||
|
### 3. Cryptor package is for data encryption and decryption.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/cryptor"
|
import "github.com/duke-git/lancet/cryptor"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesEcbEncrypt)
|
|
||||||
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesEcbDecrypt)
|
|
||||||
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCbcEncrypt)
|
|
||||||
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCbcDecrypt)
|
|
||||||
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCtrCrypt)
|
|
||||||
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCfbEncrypt)
|
|
||||||
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCfbDecrypt)
|
|
||||||
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesOfbEncrypt)
|
|
||||||
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesOfbDecrypt)
|
|
||||||
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Base64StdEncode)
|
|
||||||
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Base64StdDecode)
|
|
||||||
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesEcbEncrypt)
|
|
||||||
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesEcbDecrypt)
|
|
||||||
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCbcEncrypt)
|
|
||||||
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCbcDecrypt)
|
|
||||||
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCtrCrypt)
|
|
||||||
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCfbEncrypt)
|
|
||||||
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCfbDecrypt)
|
|
||||||
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesOfbEncrypt)
|
|
||||||
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesOfbDecrypt)
|
|
||||||
- [HmacMd5](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacMd5)
|
|
||||||
- [HmacSha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha1)
|
|
||||||
- [HmacSha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha256)
|
|
||||||
- [HmacSha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha512)
|
|
||||||
- [Md5String](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5String)
|
|
||||||
- [Md5File](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5File)
|
|
||||||
- [Sha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha1)
|
|
||||||
- [Sha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha256)
|
|
||||||
- [Sha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha512)
|
|
||||||
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#GenerateRsaKey)
|
|
||||||
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaEncrypt)
|
|
||||||
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)
|
|
||||||
|
|
||||||
### Datetime package supports date and time format and compare.
|
|
||||||
|
|
||||||
|
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesEcbEncrypt)
|
||||||
|
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesEcbDecrypt)
|
||||||
|
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCbcEncrypt)
|
||||||
|
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCbcDecrypt)
|
||||||
|
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCtrCrypt)
|
||||||
|
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCfbEncrypt)
|
||||||
|
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCfbDecrypt)
|
||||||
|
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesOfbEncrypt)
|
||||||
|
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesOfbDecrypt)
|
||||||
|
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Base64StdEncode)
|
||||||
|
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Base64StdDecode)
|
||||||
|
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesEcbEncrypt)
|
||||||
|
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesEcbDecrypt)
|
||||||
|
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCbcEncrypt)
|
||||||
|
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCbcDecrypt)
|
||||||
|
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCtrCrypt)
|
||||||
|
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCfbEncrypt)
|
||||||
|
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCfbDecrypt)
|
||||||
|
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesOfbEncrypt)
|
||||||
|
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesOfbDecrypt)
|
||||||
|
- [HmacMd5](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacMd5)
|
||||||
|
- [HmacMd5WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacMd5WithBase64)
|
||||||
|
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha1)
|
||||||
|
- [HmacSha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha1WithBase64)
|
||||||
|
- [HmacSha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha256)
|
||||||
|
- [HmacSha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha256WithBase64)
|
||||||
|
- [HmacSha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha512)
|
||||||
|
- [HmacSha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha512WithBase64)
|
||||||
|
- [Md5String](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5String)
|
||||||
|
- [Md5StringWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5StringWithBase64)
|
||||||
|
- [Md5Byte](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5Byte)
|
||||||
|
- [Md5ByteWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5ByteWithBase64)
|
||||||
|
- [Md5File](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5File)
|
||||||
|
- [Sha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha1)
|
||||||
|
- [Sha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha1WithBase64)
|
||||||
|
- [Sha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha256)
|
||||||
|
- [Sha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha256WithBase64)
|
||||||
|
- [Sha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha512)
|
||||||
|
- [Sha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha512WithBase64)
|
||||||
|
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#GenerateRsaKey)
|
||||||
|
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaEncrypt)
|
||||||
|
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaDecrypt)
|
||||||
|
- [GenerateRsaKeyPair](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#GenerateRsaKeyPair)
|
||||||
|
- [RsaEncryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaEncryptOAEP)
|
||||||
|
- [RsaDecryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaDecryptOAEP)
|
||||||
|
### 4. Datetime package supports date and time format and compare.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/datetime"
|
import "github.com/duke-git/lancet/datetime"
|
||||||
```
|
```
|
||||||
#### Function list:
|
|
||||||
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddDay)
|
|
||||||
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddHour)
|
|
||||||
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddMinute)
|
|
||||||
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)
|
|
||||||
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)
|
|
||||||
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)
|
|
||||||
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)
|
|
||||||
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)
|
|
||||||
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)
|
|
||||||
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)
|
|
||||||
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)
|
|
||||||
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)
|
|
||||||
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)
|
|
||||||
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)
|
|
||||||
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)
|
|
||||||
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDate)
|
|
||||||
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowTime)
|
|
||||||
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDateTime)
|
|
||||||
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetZeroHourTimestamp)
|
|
||||||
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNightTimestamp)
|
|
||||||
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatTimeToStr)
|
|
||||||
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatStrToTime)
|
|
||||||
|
|
||||||
### Fileutil package implements some basic functions for file operations.
|
#### Function list:
|
||||||
|
|
||||||
|
- [AddDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddDay)
|
||||||
|
- [AddHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddHour)
|
||||||
|
- [AddMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddMinute)
|
||||||
|
- [AddYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddYear)
|
||||||
|
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMinute)
|
||||||
|
- [BeginOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfHour)
|
||||||
|
- [BeginOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfDay)
|
||||||
|
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfWeek)
|
||||||
|
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMonth)
|
||||||
|
- [BeginOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfYear)
|
||||||
|
- [EndOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMinute)
|
||||||
|
- [EndOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfHour)
|
||||||
|
- [EndOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfDay)
|
||||||
|
- [EndOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfWeek)
|
||||||
|
- [EndOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMonth)
|
||||||
|
- [EndOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfYear)
|
||||||
|
- [GetNowDate](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNowDate)
|
||||||
|
- [GetNowTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNowTime)
|
||||||
|
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNowDateTime)
|
||||||
|
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetZeroHourTimestamp)
|
||||||
|
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNightTimestamp)
|
||||||
|
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#FormatTimeToStr)
|
||||||
|
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#FormatStrToTime)
|
||||||
|
- [NewUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewUnix)
|
||||||
|
- [NewUnixNow](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewUnixNow)
|
||||||
|
- [NewFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewFormat)
|
||||||
|
- [NewISO8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewISO8601)
|
||||||
|
- [ToUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToUnix)
|
||||||
|
- [ToFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToFormat)
|
||||||
|
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToFormatForTpl)
|
||||||
|
- [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToIso8601)
|
||||||
|
- [IsLeapYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#IsLeapYear)
|
||||||
|
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BetweenSeconds)
|
||||||
|
- [DayOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#DayOfYear)
|
||||||
|
- [IsWeekend](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#IsWeekend)
|
||||||
|
- [NowDateOrTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NowDateOrTime)
|
||||||
|
- [Timestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#Timestamp)
|
||||||
|
- [TimestampMilli](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#TimestampMilli)
|
||||||
|
- [TimestampMicro](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#TimestampMicro)
|
||||||
|
- [TimestampNano](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#TimestampNano)
|
||||||
|
|
||||||
|
### 5. Fileutil package implements some basic functions for file operations.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/fileutil"
|
import "github.com/duke-git/lancet/fileutil"
|
||||||
@@ -156,147 +214,203 @@ import "github.com/duke-git/lancet/fileutil"
|
|||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
|
|
||||||
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ClearFile)
|
- [ClearFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ClearFile)
|
||||||
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateFile)
|
- [CreateFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CreateFile)
|
||||||
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CopyFile)
|
- [CreateDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CreateDir)
|
||||||
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#FileMode)
|
- [CopyFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CopyFile)
|
||||||
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#MiMeType)
|
- [FileMode](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#FileMode)
|
||||||
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsExist)
|
- [MiMeType](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#MiMeType)
|
||||||
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsLink)
|
- [IsExist](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsExist)
|
||||||
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsDir)
|
- [IsLink](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsLink)
|
||||||
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ListFileNames)
|
- [IsDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsDir)
|
||||||
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#RemoveFile)
|
- [ListFileNames](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ListFileNames)
|
||||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileToString)
|
- [RemoveFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#RemoveFile)
|
||||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)
|
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileToString)
|
||||||
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)
|
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileByLine)
|
||||||
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)
|
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Zip)
|
||||||
|
- [ZipAppendEntry](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ZipAppendEntry)
|
||||||
|
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#UnZip)
|
||||||
|
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CurrentPath)
|
||||||
|
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsZipFile)
|
||||||
|
- [FileSize](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#FileSize)
|
||||||
|
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#MTime)
|
||||||
|
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Sha)
|
||||||
|
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadCsvFile)
|
||||||
|
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteCsvFile)
|
||||||
|
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteStringToFile)
|
||||||
|
- [WriteBytesToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteBytesToFile)
|
||||||
|
- [ReadFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFile)
|
||||||
|
|
||||||
### Formatter contains some functions for data formatting.
|
### 6. Formatter contains some functions for data formatting.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/formatter"
|
import "github.com/duke-git/lancet/formatter"
|
||||||
```
|
```
|
||||||
#### Function list:
|
|
||||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
|
|
||||||
|
|
||||||
### Function package can control the flow of function execution and support part of functional programming
|
#### Function list:
|
||||||
|
|
||||||
|
- [Comma](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#Comma)
|
||||||
|
- [Pretty](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#Pretty)
|
||||||
|
- [PrettyToWriter](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#PrettyToWriter)
|
||||||
|
- [DecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#DecimalBytes)
|
||||||
|
- [BinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#BinaryBytes)
|
||||||
|
- [ParseDecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#ParseDecimalBytes)
|
||||||
|
- [ParseBinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#ParseBinaryBytes)
|
||||||
|
|
||||||
|
### 7. Function package can control the flow of function execution and support part of functional programming
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/function"
|
import "github.com/duke-git/lancet/function"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/function.md#After)
|
|
||||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function.md#Before)
|
|
||||||
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function.md#Curry)
|
|
||||||
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)
|
|
||||||
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function.md#Debounced)
|
|
||||||
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)
|
|
||||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)
|
|
||||||
|
|
||||||
|
- [After](https://github.com/duke-git/lancet/blob/v1/docs/function.md#After)
|
||||||
|
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Before)
|
||||||
|
- [Curry](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Curry)
|
||||||
|
- [Compose](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Compose)
|
||||||
|
- [Debounced](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Debounced)
|
||||||
|
- [Delay](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Delay)
|
||||||
|
- [Pipeline](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Pipeline)
|
||||||
|
- [Schedule](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Schedule)
|
||||||
|
- [Watcher](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Watcher)
|
||||||
|
|
||||||
### Mathutil package implements some functions for math calculation.
|
### 8. Mathutil package implements some functions for math calculation.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/mathutil"
|
import "github.com/duke-git/lancet/mathutil"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Exponent)
|
|
||||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Fibonacci)
|
|
||||||
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Factorial)
|
|
||||||
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)
|
|
||||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)
|
|
||||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToString)
|
|
||||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)
|
|
||||||
|
|
||||||
|
- [Exponent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Exponent)
|
||||||
|
- [Fibonacci](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Fibonacci)
|
||||||
|
- [Factorial](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Factorial)
|
||||||
|
- [Percent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Percent)
|
||||||
|
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RoundToFloat)
|
||||||
|
- [RoundToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RoundToString)
|
||||||
|
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#TruncRound)
|
||||||
|
- [AngleToRadian](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#AngleToRadian)
|
||||||
|
- [RadianToAngle](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RadianToAngle)
|
||||||
|
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#PointDistance)
|
||||||
|
- [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#IsPrime)
|
||||||
|
- [GCD](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#GCD)
|
||||||
|
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#LCM)
|
||||||
|
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Cos)
|
||||||
|
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Sin)
|
||||||
|
- [Log](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Log)
|
||||||
|
|
||||||
### Netutil package contains functions to get net information and send http request.
|
### 9. Netutil package contains functions to get net information and send http request.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/netutil"
|
import "github.com/duke-git/lancet/netutil"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ConvertMapToQueryString)
|
|
||||||
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetInternalIp)
|
|
||||||
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
|
|
||||||
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
|
|
||||||
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetPublicIpInfo)
|
|
||||||
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPublicIP)
|
|
||||||
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
|
|
||||||
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
|
|
||||||
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
|
|
||||||
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)
|
|
||||||
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
|
|
||||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)
|
|
||||||
|
|
||||||
### Random package implements some basic functions to generate random int and string.
|
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#ConvertMapToQueryString)
|
||||||
|
- [EncodeUrl](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#EncodeUrl)
|
||||||
|
- [GetInternalIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetInternalIp)
|
||||||
|
- [GetIps](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetIps)
|
||||||
|
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetMacAddrs)
|
||||||
|
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetPublicIpInfo)
|
||||||
|
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetRequestPublicIp)
|
||||||
|
- [IsPublicIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsPublicIP)
|
||||||
|
- [IsInternalIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsInternalIP)
|
||||||
|
- [HttpGet](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpGet)
|
||||||
|
- [HttpDelete](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpDelete)
|
||||||
|
- [HttpPost](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpPost)
|
||||||
|
- [HttpPut](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpPut)
|
||||||
|
- [HttpPatch](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpPatch)
|
||||||
|
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#ParseHttpResponse)
|
||||||
|
- [UploadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#UploadFile)
|
||||||
|
- [DownloadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#DownloadFile)
|
||||||
|
- [IsPingConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsPingConnected)
|
||||||
|
- [IsTelnetConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsTelnetConnected)
|
||||||
|
|
||||||
|
### 10. Random package implements some basic functions to generate random int and string.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/random"
|
import "github.com/duke-git/lancet/random"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandBytes)
|
|
||||||
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)
|
|
||||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)
|
|
||||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
|
||||||
|
|
||||||
### Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
- [RandBytes](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandBytes)
|
||||||
|
- [RandInt](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandInt)
|
||||||
|
- [RandString](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandString)
|
||||||
|
- [RandUpper](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUpper)
|
||||||
|
- [RandLower](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandLower)
|
||||||
|
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeral)
|
||||||
|
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeralOrLetter)
|
||||||
|
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
|
||||||
|
- [RandUniqueIntSlice](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUniqueIntSlice)
|
||||||
|
|
||||||
|
### 11. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/retry"
|
import "github.com/duke-git/lancet/retry"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Context)
|
|
||||||
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Retry)
|
|
||||||
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryFunc)
|
|
||||||
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryDuration)
|
|
||||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)
|
|
||||||
|
|
||||||
### Slice contains some functions to manipulate slice.
|
- [Context](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#Context)
|
||||||
|
- [Retry](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#Retry)
|
||||||
|
- [RetryFunc](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryFunc)
|
||||||
|
- [RetryDuration](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryDuration)
|
||||||
|
- [RetryTimes](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryTimes)
|
||||||
|
|
||||||
|
### 12. Slice contains some functions to manipulate slice.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/slice"
|
import "github.com/duke-git/lancet/slice"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)
|
|
||||||
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)
|
|
||||||
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)
|
|
||||||
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Compact)
|
|
||||||
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Concat)
|
|
||||||
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Count)
|
|
||||||
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Difference)
|
|
||||||
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceBy)
|
|
||||||
- [DeleteByIndex](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteByIndex)
|
|
||||||
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)
|
|
||||||
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Every)
|
|
||||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)
|
|
||||||
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)
|
|
||||||
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLast)
|
|
||||||
- [FlattenDeep](#FlattenDeep)
|
|
||||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)
|
|
||||||
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)
|
|
||||||
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IntSlice)
|
|
||||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InterfaceSlice)
|
|
||||||
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Intersection)
|
|
||||||
- [InsertByIndex](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InsertByIndex)
|
|
||||||
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Map)
|
|
||||||
- [ReverseSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReverseSlice)
|
|
||||||
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)
|
|
||||||
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)
|
|
||||||
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortByField)
|
|
||||||
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Some)
|
|
||||||
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#StringSlice)
|
|
||||||
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Unique)
|
|
||||||
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Union)
|
|
||||||
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateByIndex)
|
|
||||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)
|
|
||||||
|
|
||||||
### Strutil package contains some functions to manipulate string.
|
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#AppendIfAbsent)
|
||||||
|
- [Contain](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Contain)
|
||||||
|
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ContainSubSlice)
|
||||||
|
- [Chunk](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Chunk)
|
||||||
|
- [Compact](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Compact)
|
||||||
|
- [Concat](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Concat)
|
||||||
|
- [Count](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Count)
|
||||||
|
- [Difference](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Difference)
|
||||||
|
- [DifferenceBy](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#DifferenceBy)
|
||||||
|
- [DeleteByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#DeleteByIndex)
|
||||||
|
- [Drop](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Drop)
|
||||||
|
- [Every](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Every)
|
||||||
|
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Equal)
|
||||||
|
- [EqualWith](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#EqualWith)
|
||||||
|
- [Filter](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Filter)
|
||||||
|
- [Find](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Find)
|
||||||
|
- [FindLast](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#FindLast)
|
||||||
|
- [FlattenDeep](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#FlattenDeep)
|
||||||
|
- [ForEach](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ForEach)
|
||||||
|
- [GroupBy](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#GroupBy)
|
||||||
|
- [IntSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#IntSlice)
|
||||||
|
- [IndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#IndexOf)
|
||||||
|
- [LastIndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#LastIndexOf)
|
||||||
|
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#InterfaceSlice)
|
||||||
|
- [Intersection](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Intersection)
|
||||||
|
- [InsertByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#InsertByIndex)
|
||||||
|
- [Map](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Map)
|
||||||
|
- [ReverseSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ReverseSlice)
|
||||||
|
- [Reduce](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Reduce)
|
||||||
|
- [Shuffle](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Shuffle)
|
||||||
|
- [SortByField](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#SortByField)
|
||||||
|
- [Some](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Some)
|
||||||
|
- [StringSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#StringSlice)
|
||||||
|
- [ToSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ToSlice)
|
||||||
|
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ToSlice)
|
||||||
|
- [Unique](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Unique)
|
||||||
|
- [UniqueBy](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#UniqueBy)
|
||||||
|
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Union)
|
||||||
|
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#UpdateByIndex)
|
||||||
|
- [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Without)
|
||||||
|
- [Join](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Join)
|
||||||
|
|
||||||
|
### 13. Strutil package contains some functions to manipulate string.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/strutil"
|
import "github.com/duke-git/lancet/strutil"
|
||||||
@@ -304,73 +418,111 @@ import "github.com/duke-git/lancet/strutil"
|
|||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
|
|
||||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)
|
- [After](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#After)
|
||||||
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)
|
- [AfterLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#AfterLast)
|
||||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)
|
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Before)
|
||||||
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)
|
- [BeforeLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#BeforeLast)
|
||||||
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#CamelCase)
|
- [CamelCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#CamelCase)
|
||||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)
|
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Capitalize)
|
||||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)
|
- [ContainsAll](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ContainsAll)
|
||||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)
|
- [ContainsAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ContainsAny)
|
||||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)
|
- [IsString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IsString)
|
||||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
|
- [KebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#KebabCase)
|
||||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
|
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperKebabCase)
|
||||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
|
- [LowerFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#LowerFirst)
|
||||||
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ReverseStr)
|
- [UpperFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperFirst)
|
||||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
|
- [Pad](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Pad)
|
||||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
|
- [PadEnd](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#PadEnd)
|
||||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
|
- [PadStart](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#PadStart)
|
||||||
|
- [Reverse](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Reverse)
|
||||||
### System package contain some functions about os, runtime, shell command.
|
- [SnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SnakeCase)
|
||||||
|
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperSnakeCase)
|
||||||
|
- [SplitEx](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitEx)
|
||||||
|
- [Wrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Wrap)
|
||||||
|
- [Unwrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Unwrap)
|
||||||
|
- [SplitWords](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitWords)
|
||||||
|
- [WordCount](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#WordCount)
|
||||||
|
- [RemoveNonPrintable](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#RemoveNonPrintable)
|
||||||
|
- [StringToBytes](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#StringToBytes)
|
||||||
|
- [BytesToString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#BytesToString)
|
||||||
|
- [IsBlank](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IsBlank)
|
||||||
|
- [HasPrefixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HasPrefixAny)
|
||||||
|
- [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HasSuffixAny)
|
||||||
|
- [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IndexOffset)
|
||||||
|
- [ReplaceWithMap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ReplaceWithMap)
|
||||||
|
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Trim)
|
||||||
|
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitAndTrim)
|
||||||
|
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HideString)
|
||||||
|
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#RemoveWhiteSpace)
|
||||||
|
### 14. System package contain some functions about os, runtime, shell command.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/system"
|
import "github.com/duke-git/lancet/system"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsWindows)
|
|
||||||
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsLinux)
|
|
||||||
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsMac)
|
|
||||||
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsEnv)
|
|
||||||
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#SetOsEnv)
|
|
||||||
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#RemoveOsEnv)
|
|
||||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#CompareOsEnv)
|
|
||||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system.md#ExecCommand)
|
|
||||||
|
|
||||||
### Validator package contains some functions for data validation.
|
- [IsWindows](https://github.com/duke-git/lancet/blob/v1/docs/system.md#IsWindows)
|
||||||
|
- [IsLinux](https://github.com/duke-git/lancet/blob/v1/docs/system.md#IsLinux)
|
||||||
|
- [IsMac](https://github.com/duke-git/lancet/blob/v1/docs/system.md#IsMac)
|
||||||
|
- [GetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#GetOsEnv)
|
||||||
|
- [SetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#SetOsEnv)
|
||||||
|
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#RemoveOsEnv)
|
||||||
|
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#CompareOsEnv)
|
||||||
|
- [ExecCommand](https://github.com/duke-git/lancet/blob/v1/docs/system.md#ExecCommand)
|
||||||
|
- [GetOsBits](https://github.com/duke-git/lancet/blob/v1/docs/system.md#GetOsBits)
|
||||||
|
|
||||||
|
### 15. Validator package contains some functions for data validation.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/validator"
|
import "github.com/duke-git/lancet/validator"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
|
|
||||||
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainChinese)
|
- [ContainChinese](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainChinese)
|
||||||
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLetter)
|
- [ContainLetter](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainLetter)
|
||||||
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLower)
|
- [ContainLower](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainLower)
|
||||||
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainUpper)
|
- [ContainUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainUpper)
|
||||||
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAlpha)
|
- [IsAlpha](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAlpha)
|
||||||
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllUpper)
|
- [IsAllUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAllUpper)
|
||||||
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllLower)
|
- [IsAllLower](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAllLower)
|
||||||
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsBase64)
|
- [IsBase64](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsBase64)
|
||||||
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseMobile)
|
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChineseMobile)
|
||||||
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseIdNum)
|
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChineseIdNum)
|
||||||
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChinesePhone)
|
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChinesePhone)
|
||||||
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsCreditCard)
|
- [IsCreditCard](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsCreditCard)
|
||||||
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsDns)
|
- [IsDns](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsDns)
|
||||||
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmail)
|
- [IsEmail](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsEmail)
|
||||||
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmptyString)
|
- [IsEmptyString](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsEmptyString)
|
||||||
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)
|
- [IsInt](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsInt)
|
||||||
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)
|
- [IsFloat](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsFloat)
|
||||||
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsJSON)
|
- [IsNumber](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsNumber)
|
||||||
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsRegexMatch)
|
- [IsIntStr](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIntStr)
|
||||||
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)
|
- [IsFloatStr](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsFloatStr)
|
||||||
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIp)
|
- [IsNumberStr](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsNumberStr)
|
||||||
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV4)
|
- [IsJSON](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsJSON)
|
||||||
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV6)
|
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsRegexMatch)
|
||||||
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)
|
- [IsIp](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIp)
|
||||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
|
- [IsIpV4](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIpV4)
|
||||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
|
- [IsIpV6](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIpV6)
|
||||||
|
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsStrongPassword)
|
||||||
|
- [IsUrl](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsUrl)
|
||||||
|
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsWeakPassword)
|
||||||
|
- [IsZeroValue](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsZeroValue)
|
||||||
|
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsGBK)
|
||||||
|
- [IsASCII](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsASCII)
|
||||||
|
- [IsPrintable](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsPrintable)
|
||||||
|
- [IsBin](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsBin)
|
||||||
|
- [IsHex](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsHex)
|
||||||
|
- [IsBase64URL](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsBase64URL)
|
||||||
|
- [IsJWT](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsJWT)
|
||||||
|
- [IsVisa](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsVisa)
|
||||||
|
- [IsMasterCard](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsMasterCard)
|
||||||
|
- [IsAmericanExpress](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAmericanExpress)
|
||||||
|
- [IsUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsUnionPay)
|
||||||
|
- [IsChinaUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChinaUnionPay)
|
||||||
|
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
||||||
@@ -380,4 +532,4 @@ I really appreciate any code commits which make lancet lib powerful. Please foll
|
|||||||
2. Create your feature branch.
|
2. Create your feature branch.
|
||||||
3. Commit your changes.
|
3. Commit your changes.
|
||||||
4. Push to the branch
|
4. Push to the branch
|
||||||
5. Create new pull request.
|
5. Create new pull request.
|
||||||
|
|||||||
609
README_zh-CN.md
609
README_zh-CN.md
@@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
<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)
|
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
[](https://codecov.io/gh/duke-git/lancet)
|
[](https://codecov.io/gh/duke-git/lancet)
|
||||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
[](https://github.com/duke-git/lancet/blob/v1/LICENSE)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -20,13 +20,12 @@
|
|||||||
|
|
||||||
简体中文 | [English](./README.md)
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
- 👏 全面、高效、可复用
|
- 👏 全面、高效、可复用
|
||||||
- 💪 180+常用go工具函数,支持string、slice、datetime、net、crypt...
|
- 💪 400+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
|
||||||
- 💅 只依赖go标准库
|
- 💅 只依赖 go 标准库
|
||||||
- 🌍 所有导出函数单元测试覆盖率100%
|
- 🌍 所有导出函数单元测试覆盖率 100%
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
@@ -36,7 +35,7 @@ go get github.com/duke-git/lancet
|
|||||||
|
|
||||||
## 用法
|
## 用法
|
||||||
|
|
||||||
lancet是以包的结构组织代码的,使用时需要导入相应的包名。例如:如果使用字符串相关函数,需要导入strutil包:
|
lancet 是以包的结构组织代码的,使用时需要导入相应的包名。例如:如果使用字符串相关函数,需要导入 strutil 包:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/strutil"
|
import "github.com/duke-git/lancet/strutil"
|
||||||
@@ -44,7 +43,7 @@ import "github.com/duke-git/lancet/strutil"
|
|||||||
|
|
||||||
## 例子
|
## 例子
|
||||||
|
|
||||||
此处以字符串工具函数ReverseStr(逆序字符串)为例,需要导入strutil包:
|
此处以字符串工具函数 Reverse(逆序字符串)为例,需要导入 strutil 包:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -56,99 +55,159 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := "hello"
|
s := "hello"
|
||||||
rs := strutil.ReverseStr(s)
|
rs := strutil.Reverse(s)
|
||||||
fmt.Println(rs) //olleh
|
fmt.Println(rs) //olleh
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## API文档
|
## API 文档
|
||||||
### convertor转换器包支持一些常见的数据类型转换。
|
|
||||||
|
|
||||||
|
### 1. compare包提供几个轻量级的类型比较函数。
|
||||||
|
```go
|
||||||
|
import "github.com/duke-git/lancet/compare"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Function list:
|
||||||
|
|
||||||
|
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#Equal)
|
||||||
|
- [EqualValue](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#EqualValue)
|
||||||
|
- [LessThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessThan)
|
||||||
|
- [GreaterThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterThan)
|
||||||
|
- [LessOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessOrEqual)
|
||||||
|
- [GreaterOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterOrEqual)
|
||||||
|
|
||||||
|
### 2. convertor转换器包支持一些常见的数据类型转换。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/convertor"
|
import "github.com/duke-git/lancet/convertor"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorHexToRGB)
|
|
||||||
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorRGBToHex)
|
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ColorHexToRGB)
|
||||||
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBool)
|
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ColorRGBToHex)
|
||||||
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBytes)
|
- [ToBool](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToBool)
|
||||||
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChar)
|
- [ToBytes](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToBytes)
|
||||||
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInt)
|
- [ToChar](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToChar)
|
||||||
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToJson)
|
- [ToChannel](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToChannel)
|
||||||
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
|
- [ToInt](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInt)
|
||||||
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
|
- [ToJson](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToJson)
|
||||||
|
- [ToString](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToString)
|
||||||
### cryptor加密包支持数据加密和解密,获取md5,hash值。支持base64, md5, hmac, aes, des, rsa。
|
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#StructToMap)
|
||||||
|
- [EncodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#EncodeByte)
|
||||||
|
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DecodeByte)
|
||||||
|
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DeepClone)
|
||||||
|
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#CopyProperties)
|
||||||
|
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInterface)
|
||||||
|
- [Utf8ToGbk](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#Utf8ToGbk)
|
||||||
|
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#GbkToUtf8)
|
||||||
|
### 3. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/cryptor"
|
import "github.com/duke-git/lancet/cryptor"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbEncrypt)
|
|
||||||
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbDecrypt)
|
|
||||||
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcEncrypt)
|
|
||||||
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcDecrypt)
|
|
||||||
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCtrCrypt)
|
|
||||||
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbEncrypt)
|
|
||||||
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbDecrypt)
|
|
||||||
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbEncrypt)
|
|
||||||
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbDecrypt)
|
|
||||||
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdEncode)
|
|
||||||
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdDecode)
|
|
||||||
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbEncrypt)
|
|
||||||
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbDecrypt)
|
|
||||||
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcEncrypt)
|
|
||||||
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcDecrypt)
|
|
||||||
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCtrCrypt)
|
|
||||||
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbEncrypt)
|
|
||||||
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbDecrypt)
|
|
||||||
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbEncrypt)
|
|
||||||
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbDecrypt)
|
|
||||||
- [HmacMd5](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5)
|
|
||||||
- [HmacSha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1)
|
|
||||||
- [HmacSha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256)
|
|
||||||
- [HmacSha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512)
|
|
||||||
- [Md5String](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5String)
|
|
||||||
- [Md5File](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5File)
|
|
||||||
- [Sha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1)
|
|
||||||
- [Sha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256)
|
|
||||||
- [Sha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512)
|
|
||||||
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#GenerateRsaKey)
|
|
||||||
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaEncrypt)
|
|
||||||
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)
|
|
||||||
|
|
||||||
### datetime日期时间处理包,格式化日期,比较日期。
|
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesEcbEncrypt)
|
||||||
|
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesEcbDecrypt)
|
||||||
|
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCbcEncrypt)
|
||||||
|
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCbcDecrypt)
|
||||||
|
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCtrCrypt)
|
||||||
|
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCfbEncrypt)
|
||||||
|
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCfbDecrypt)
|
||||||
|
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesOfbEncrypt)
|
||||||
|
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesOfbDecrypt)
|
||||||
|
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Base64StdEncode)
|
||||||
|
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Base64StdDecode)
|
||||||
|
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesEcbEncrypt)
|
||||||
|
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesEcbDecrypt)
|
||||||
|
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCbcEncrypt)
|
||||||
|
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCbcDecrypt)
|
||||||
|
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCtrCrypt)
|
||||||
|
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCfbEncrypt)
|
||||||
|
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCfbDecrypt)
|
||||||
|
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbEncrypt)
|
||||||
|
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbDecrypt)
|
||||||
|
- [HmacMd5](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacMd5)
|
||||||
|
- [HmacMd5WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacMd5WithBase64)
|
||||||
|
md#HmacSha256WithBase64)
|
||||||
|
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha1)
|
||||||
|
- [HmacSha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha1WithBase64)
|
||||||
|
- [HmacSha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha256)
|
||||||
|
- [HmacSha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha256WithBase64)
|
||||||
|
- [HmacSha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha512)
|
||||||
|
- [HmacSha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha512WithBase64)
|
||||||
|
- [Md5String](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5String)
|
||||||
|
- [Md5StringWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5StringWithBase64)
|
||||||
|
- [Md5Byte](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5Byte)
|
||||||
|
- [Md5ByteWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5ByteWithBase64)
|
||||||
|
- [Md5File](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5File)
|
||||||
|
- [Sha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha1)
|
||||||
|
- [Sha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha1WithBase64)
|
||||||
|
- [Sha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha256)
|
||||||
|
- [Sha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha256WithBase64)
|
||||||
|
- [Sha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha512)
|
||||||
|
- [Sha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha512WithBase64)
|
||||||
|
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#GenerateRsaKey)
|
||||||
|
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncrypt)
|
||||||
|
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecrypt)
|
||||||
|
- [GenerateRsaKeyPair](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#GenerateRsaKeyPair)
|
||||||
|
- [RsaEncryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncryptOAEP)
|
||||||
|
- [RsaDecryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecryptOAEP)
|
||||||
|
|
||||||
|
|
||||||
|
### 4. datetime 日期时间处理包,格式化日期,比较日期。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/datetime"
|
import "github.com/duke-git/lancet/datetime"
|
||||||
```
|
```
|
||||||
#### 函数列表:
|
|
||||||
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddDay)
|
|
||||||
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddHour)
|
|
||||||
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddMinute)
|
|
||||||
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)
|
|
||||||
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)
|
|
||||||
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)
|
|
||||||
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)
|
|
||||||
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)
|
|
||||||
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)
|
|
||||||
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)
|
|
||||||
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)
|
|
||||||
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)
|
|
||||||
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)
|
|
||||||
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)
|
|
||||||
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)
|
|
||||||
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDate)
|
|
||||||
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowTime)
|
|
||||||
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDateTime)
|
|
||||||
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetZeroHourTimestamp)
|
|
||||||
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNightTimestamp)
|
|
||||||
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatTimeToStr)
|
|
||||||
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime)
|
|
||||||
|
|
||||||
### fileutil包支持文件基本操作。
|
#### 函数列表:
|
||||||
|
|
||||||
|
- [AddDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddDay)
|
||||||
|
- [AddHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddHour)
|
||||||
|
- [AddMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddMinute)
|
||||||
|
- [AddYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddYear)
|
||||||
|
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMinute)
|
||||||
|
- [BeginOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfHour)
|
||||||
|
- [BeginOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfDay)
|
||||||
|
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfWeek)
|
||||||
|
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMonth)
|
||||||
|
- [BeginOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfYear)
|
||||||
|
- [EndOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMinute)
|
||||||
|
- [EndOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfHour)
|
||||||
|
- [EndOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfDay)
|
||||||
|
- [EndOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfWeek)
|
||||||
|
- [EndOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMonth)
|
||||||
|
- [EndOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfYear)
|
||||||
|
- [GetNowDate](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowDate)
|
||||||
|
- [GetNowTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowTime)
|
||||||
|
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowDateTime)
|
||||||
|
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetZeroHourTimestamp)
|
||||||
|
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNightTimestamp)
|
||||||
|
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#FormatTimeToStr)
|
||||||
|
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#FormatStrToTime)
|
||||||
|
- [NewUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewUnix)
|
||||||
|
- [NewUnixNow](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewUnixNow)
|
||||||
|
- [NewFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewFormat)
|
||||||
|
- [NewISO8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewISO8601)
|
||||||
|
- [ToUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToUnix)
|
||||||
|
- [ToFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormat)
|
||||||
|
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormatForTpl)
|
||||||
|
- [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToIso8601)
|
||||||
|
- [IsLeapYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsLeapYear)
|
||||||
|
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#BetweenSeconds)
|
||||||
|
- [DayOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#DayOfYear)
|
||||||
|
- [IsWeekend](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsWeekend)
|
||||||
|
- [NowDateOrTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NowDateOrTime)
|
||||||
|
- [Timestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#Timestamp)
|
||||||
|
- [TimestampMilli](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampMilli)
|
||||||
|
- [TimestampMicro](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampMicro)
|
||||||
|
- [TimestampNano](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampNano)
|
||||||
|
|
||||||
|
### 5. fileutil 包支持文件基本操作。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/fileutil"
|
import "github.com/duke-git/lancet/fileutil"
|
||||||
@@ -156,147 +215,202 @@ import "github.com/duke-git/lancet/fileutil"
|
|||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
|
|
||||||
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ClearFile)
|
- [ClearFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ClearFile)
|
||||||
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CreateFile)
|
- [CreateFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CreateFile)
|
||||||
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CopyFile)
|
- [CreateDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CreateDir)
|
||||||
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#FileMode)
|
- [CopyFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CopyFile)
|
||||||
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#MiMeType)
|
- [FileMode](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#FileMode)
|
||||||
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsExist)
|
- [MiMeType](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MiMeType)
|
||||||
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsLink)
|
- [IsExist](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsExist)
|
||||||
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsDir)
|
- [IsLink](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsLink)
|
||||||
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ListFileNames)
|
- [IsDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsDir)
|
||||||
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#RemoveFile)
|
- [ListFileNames](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ListFileNames)
|
||||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileToString)
|
- [RemoveFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#RemoveFile)
|
||||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileByLine)
|
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileToString)
|
||||||
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)
|
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileByLine)
|
||||||
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)
|
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Zip)
|
||||||
|
- [ZipAppendEntry](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ZipAppendEntry)
|
||||||
|
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#UnZip)
|
||||||
|
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CurrentPath)
|
||||||
|
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsZipFile)
|
||||||
|
- [FileSize](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#FileSize)
|
||||||
|
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MTime)
|
||||||
|
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Sha)
|
||||||
|
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadCsvFile)
|
||||||
|
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteCsvFile)
|
||||||
|
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteStringToFile)
|
||||||
|
- [WriteBytesToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteBytesToFile)
|
||||||
|
- [ReadFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFile)
|
||||||
|
|
||||||
### formatter格式化器包含一些数据格式化处理方法。
|
### 6. formatter 格式化器包含一些数据格式化处理方法。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/formatter"
|
import "github.com/duke-git/lancet/formatter"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
|
|
||||||
|
|
||||||
|
- [Comma](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#Comma)
|
||||||
|
- [Pretty](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#Pretty)
|
||||||
|
- [PrettyToWriter](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#PrettyToWriter)
|
||||||
|
- [DecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#DecimalBytes)
|
||||||
|
- [BinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#BinaryBytes)
|
||||||
|
- [ParseDecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseDecimalBytes)
|
||||||
|
- [ParseBinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseBinaryBytes)
|
||||||
|
|
||||||
### function函数包控制函数执行流程,包含部分函数式编程。
|
### 7. function 函数包控制函数执行流程,包含部分函数式编程。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/function"
|
import "github.com/duke-git/lancet/function"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)
|
|
||||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)
|
|
||||||
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Curry)
|
|
||||||
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)
|
|
||||||
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)
|
|
||||||
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)
|
|
||||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
|
|
||||||
|
|
||||||
### mathutil包实现了一些数学计算的函数。
|
- [After](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#After)
|
||||||
|
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Before)
|
||||||
|
- [Curry](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Curry)
|
||||||
|
- [Compose](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Compose)
|
||||||
|
- [Debounced](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Debounced)
|
||||||
|
- [Delay](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Delay)
|
||||||
|
- [Pipeline](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Pipeline)
|
||||||
|
- [Schedule](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Schedule)
|
||||||
|
- [Watcher](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Watcher)
|
||||||
|
|
||||||
|
### 8. mathutil 包实现了一些数学计算的函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/mathutil"
|
import "github.com/duke-git/lancet/mathutil"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Exponent)
|
|
||||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Fibonacci)
|
|
||||||
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Factorial)
|
|
||||||
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)
|
|
||||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)
|
|
||||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
|
|
||||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
|
|
||||||
|
|
||||||
### netutil网络包支持获取ip地址,发送http请求。
|
- [Exponent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Exponent)
|
||||||
|
- [Fibonacci](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Fibonacci)
|
||||||
|
- [Factorial](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Factorial)
|
||||||
|
- [Percent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Percent)
|
||||||
|
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToFloat)
|
||||||
|
- [RoundToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToString)
|
||||||
|
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#TruncRound)
|
||||||
|
- [AngleToRadian](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#AngleToRadian)
|
||||||
|
- [RadianToAngle](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RadianToAngle)
|
||||||
|
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#PointDistance)
|
||||||
|
- [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#IsPrime)
|
||||||
|
- [GCD](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#GCD)
|
||||||
|
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#LCM)
|
||||||
|
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Cos)
|
||||||
|
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Sin)
|
||||||
|
- [Log](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Log)
|
||||||
|
### 9. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/netutil"
|
import "github.com/duke-git/lancet/netutil"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString)
|
|
||||||
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp)
|
|
||||||
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
|
|
||||||
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
|
|
||||||
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)
|
|
||||||
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)
|
|
||||||
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
|
|
||||||
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
|
|
||||||
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
|
|
||||||
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
|
|
||||||
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
|
|
||||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
|
|
||||||
|
|
||||||
### random随机数生成器包,可以生成随机[]bytes, int, string。
|
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#ConvertMapToQueryString)
|
||||||
|
- [EncodeUrl](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#EncodeUrl)
|
||||||
|
- [GetInternalIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetInternalIp)
|
||||||
|
- [GetIps](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetIps)
|
||||||
|
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetMacAddrs)
|
||||||
|
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetPublicIpInfo)
|
||||||
|
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetRequestPublicIp)
|
||||||
|
- [IsPublicIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsPublicIP)
|
||||||
|
- [IsInternalIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsInternalIP)
|
||||||
|
- [HttpGet](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpGet)
|
||||||
|
- [HttpDelete](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpDelete)
|
||||||
|
- [HttpPost](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPost)
|
||||||
|
- [HttpPut](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPut)
|
||||||
|
- [HttpPatch](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPatch)
|
||||||
|
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#ParseHttpResponse)
|
||||||
|
- [UploadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#UploadFile)
|
||||||
|
- [DownloadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#DownloadFile)
|
||||||
|
- [IsPingConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsPingConnected)
|
||||||
|
- [IsTelnetConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsTelnetConnected)
|
||||||
|
|
||||||
|
### 10. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/random"
|
import "github.com/duke-git/lancet/random"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)
|
|
||||||
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)
|
- [RandBytes](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandBytes)
|
||||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)
|
- [RandInt](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandInt)
|
||||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
- [RandString](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandString)
|
||||||
### retry重试执行函数直到函数运行成功或被context cancel。
|
- [RandUpper](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandUpper)
|
||||||
|
- [RandLower](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandLower)
|
||||||
|
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeral)
|
||||||
|
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeralOrLetter)
|
||||||
|
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
|
||||||
|
- [RandUniqueIntSlice](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUniqueIntSlice)
|
||||||
|
|
||||||
|
### 11. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/retry"
|
import "github.com/duke-git/lancet/retry"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Context)
|
|
||||||
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Retry)
|
|
||||||
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryFunc)
|
|
||||||
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)
|
|
||||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
|
|
||||||
|
|
||||||
|
- [Context](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#Context)
|
||||||
|
- [Retry](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#Retry)
|
||||||
|
- [RetryFunc](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryFunc)
|
||||||
|
- [RetryDuration](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryDuration)
|
||||||
|
- [RetryTimes](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryTimes)
|
||||||
|
|
||||||
### slice包包含操作切片的方法集合。
|
### 12. slice 包包含操作切片的方法集合。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/slice"
|
import "github.com/duke-git/lancet/slice"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)
|
|
||||||
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)
|
|
||||||
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)
|
|
||||||
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)
|
|
||||||
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)
|
|
||||||
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)
|
|
||||||
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)
|
|
||||||
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)
|
|
||||||
- [DeleteByIndex](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteByIndex)
|
|
||||||
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)
|
|
||||||
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)
|
|
||||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)
|
|
||||||
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)
|
|
||||||
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)
|
|
||||||
- [FlattenDeep](#FlattenDeep)
|
|
||||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)
|
|
||||||
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)
|
|
||||||
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)
|
|
||||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)
|
|
||||||
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Intersection)
|
|
||||||
- [InsertByIndex](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InsertByIndex)
|
|
||||||
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)
|
|
||||||
- [ReverseSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReverseSlice)
|
|
||||||
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)
|
|
||||||
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)
|
|
||||||
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)
|
|
||||||
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)
|
|
||||||
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#StringSlice)
|
|
||||||
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)
|
|
||||||
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Union)
|
|
||||||
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UpdateByIndex)
|
|
||||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
|
|
||||||
|
|
||||||
|
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#AppendIfAbsent)
|
||||||
|
- [Contain](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Contain)
|
||||||
|
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ContainSubSlice)
|
||||||
|
- [Chunk](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Chunk)
|
||||||
|
- [Compact](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Compact)
|
||||||
|
- [Concat](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Concat)
|
||||||
|
- [Count](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Count)
|
||||||
|
- [Difference](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Difference)
|
||||||
|
- [DifferenceBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#DifferenceBy)
|
||||||
|
- [DeleteByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#DeleteByIndex)
|
||||||
|
- [Drop](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Drop)
|
||||||
|
- [Every](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Every)
|
||||||
|
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Equal)
|
||||||
|
- [EqualWith](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#EqualWith)
|
||||||
|
- [Filter](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Filter)
|
||||||
|
- [Find](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Find)
|
||||||
|
- [FindLast](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#FindLast)
|
||||||
|
- [FlattenDeep](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#FlattenDeep)
|
||||||
|
- [ForEach](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ForEach)
|
||||||
|
- [GroupBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#GroupBy)
|
||||||
|
- [IntSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#IntSlice)
|
||||||
|
- [IndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#IndexOf)
|
||||||
|
- [LastIndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#LastIndexOf)
|
||||||
|
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#InterfaceSlice)
|
||||||
|
- [Intersection](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Intersection)
|
||||||
|
- [InsertByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#InsertByIndex)
|
||||||
|
- [Map](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Map)
|
||||||
|
- [ReverseSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ReverseSlice)
|
||||||
|
- [Reduce](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Reduce)
|
||||||
|
- [Shuffle](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Shuffle)
|
||||||
|
- [SortByField](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#SortByField)
|
||||||
|
- [Some](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Some)
|
||||||
|
- [StringSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#StringSlice)
|
||||||
|
- [ToSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ToSlice)
|
||||||
|
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ToSlice)
|
||||||
|
- [Unique](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Unique)
|
||||||
|
- [UniqueBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UniqueBy)
|
||||||
|
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Union)
|
||||||
|
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UpdateByIndex)
|
||||||
|
- [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Without)
|
||||||
|
- [Join](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Join)
|
||||||
|
|
||||||
### strutil包含处理字符串的相关函数。
|
### 13. strutil 包含处理字符串的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/strutil"
|
import "github.com/duke-git/lancet/strutil"
|
||||||
@@ -304,81 +418,118 @@ import "github.com/duke-git/lancet/strutil"
|
|||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
|
|
||||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#After)
|
- [After](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#After)
|
||||||
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#AfterLast)
|
- [AfterLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#AfterLast)
|
||||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Before)
|
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Before)
|
||||||
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#BeforeLast)
|
- [BeforeLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#BeforeLast)
|
||||||
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#CamelCase)
|
- [CamelCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#CamelCase)
|
||||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)
|
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Capitalize)
|
||||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)
|
- [ContainsAll](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAll)
|
||||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)
|
- [ContainsAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAny)
|
||||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)
|
- [IsString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IsString)
|
||||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
|
- [KebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#KebabCase)
|
||||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
|
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperKebabCase)
|
||||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
|
- [LowerFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#LowerFirst)
|
||||||
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ReverseStr)
|
- [UpperFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperFirst)
|
||||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
|
- [Pad](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Pad)
|
||||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
- [PadEnd](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadEnd)
|
||||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
- [PadStart](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadStart)
|
||||||
|
- [Reverse](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Reverse)
|
||||||
|
- [SnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SnakeCase)
|
||||||
|
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperSnakeCase)
|
||||||
|
- [SplitEx](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitEx)
|
||||||
|
- [Wrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Wrap)
|
||||||
|
- [Unwrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Unwrap)
|
||||||
|
- [SplitWords](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitWords)
|
||||||
|
- [WordCount](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#WordCount)
|
||||||
|
- [RemoveNonPrintable](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveNonPrintable)
|
||||||
|
- [StringToBytes](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#StringToBytes)
|
||||||
|
- [BytesToString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#BytesToString)
|
||||||
|
- [IsBlank](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IsBlank)
|
||||||
|
- [HasPrefixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasPrefixAny)
|
||||||
|
- [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasSuffixAny)
|
||||||
|
- [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IndexOffset)
|
||||||
|
- [ReplaceWithMap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ReplaceWithMap)
|
||||||
|
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Trim)
|
||||||
|
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitAndTrim)
|
||||||
|
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HideString)
|
||||||
|
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveWhiteSpace)
|
||||||
|
|
||||||
### system包含os, runtime, shell command相关函数。
|
### 14. system 包含 os, runtime, shell command 相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/system"
|
import "github.com/duke-git/lancet/system"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsWindows)
|
|
||||||
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsLinux)
|
|
||||||
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsMac)
|
|
||||||
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsEnv)
|
|
||||||
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#SetOsEnv)
|
|
||||||
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#RemoveOsEnv)
|
|
||||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#CompareOsEnv)
|
|
||||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
|
|
||||||
|
|
||||||
### validator验证器包,包含常用字符串格式验证函数。
|
- [IsWindows](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsWindows)
|
||||||
|
- [IsLinux](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsLinux)
|
||||||
|
- [IsMac](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsMac)
|
||||||
|
- [GetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#GetOsEnv)
|
||||||
|
- [SetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#SetOsEnv)
|
||||||
|
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#RemoveOsEnv)
|
||||||
|
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#CompareOsEnv)
|
||||||
|
- [ExecCommand](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#ExecCommand)
|
||||||
|
- [GetOsBits](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#GetOsBits)
|
||||||
|
|
||||||
|
### 15. validator 验证器包,包含常用字符串格式验证函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/validator"
|
import "github.com/duke-git/lancet/validator"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
|
|
||||||
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainChinese)
|
- [ContainChinese](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainChinese)
|
||||||
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLetter)
|
- [ContainLetter](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainLetter)
|
||||||
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLower)
|
- [ContainLower](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainLower)
|
||||||
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainUpper)
|
- [ContainUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainUpper)
|
||||||
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAlpha)
|
- [IsAlpha](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAlpha)
|
||||||
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllUpper)
|
- [IsAllUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAllUpper)
|
||||||
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllLower)
|
- [IsAllLower](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAllLower)
|
||||||
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsBase64)
|
- [IsBase64](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBase64)
|
||||||
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseMobile)
|
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChineseMobile)
|
||||||
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseIdNum)
|
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChineseIdNum)
|
||||||
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChinesePhone)
|
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChinesePhone)
|
||||||
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsCreditCard)
|
- [IsCreditCard](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsCreditCard)
|
||||||
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsDns)
|
- [IsDns](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsDns)
|
||||||
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmail)
|
- [IsEmail](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsEmail)
|
||||||
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmptyString)
|
- [IsEmptyString](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsEmptyString)
|
||||||
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloatStr)
|
- [IsInt](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsInt)
|
||||||
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)
|
- [IsFloat](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsFloat)
|
||||||
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsJSON)
|
- [IsNumber](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsNumber)
|
||||||
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsRegexMatch)
|
- [IsIntStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIntStr)
|
||||||
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)
|
- [IsFloatStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsFloatStr)
|
||||||
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIp)
|
- [IsNumberStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsNumberStr)
|
||||||
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV4)
|
- [IsJSON](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsJSON)
|
||||||
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV6)
|
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsRegexMatch)
|
||||||
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)
|
- [IsIp](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIp)
|
||||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
|
- [IsIpV4](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIpV4)
|
||||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
|
- [IsIpV6](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIpV6)
|
||||||
|
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsStrongPassword)
|
||||||
|
- [IsUrl](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsUrl)
|
||||||
|
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsWeakPassword)
|
||||||
|
- [IsZeroValue](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsZeroValue)
|
||||||
|
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsGBK)
|
||||||
|
- [IsASCII](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsASCII)
|
||||||
|
- [IsPrintable](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsPrintable)
|
||||||
|
- [IsBin](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBin)
|
||||||
|
- [IsHex](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsHex)
|
||||||
|
- [IsBase64URL](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBase64URL)
|
||||||
|
- [IsJWT](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsJWT)
|
||||||
|
- [IsVisa](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsVisa)
|
||||||
|
- [IsMasterCard](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsMasterCard)
|
||||||
|
- [IsAmericanExpress](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAmericanExpress)
|
||||||
|
- [IsUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsUnionPay)
|
||||||
|
- [IsChinaUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChinaUnionPay)
|
||||||
|
|
||||||
## 如何贡献代码
|
## 如何贡献代码
|
||||||
|
|
||||||
非常感激任何的代码提交以使lancet的功能越来越强大。创建pull request时请遵守以下规则。
|
非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。
|
||||||
|
|
||||||
1. Fork lancet仓库。
|
1. Fork lancet 仓库。
|
||||||
2. 创建自己的特性分支。
|
2. 创建自己的特性分支。
|
||||||
3. 提交变更。
|
3. 提交变更。
|
||||||
4. Push分支。
|
4. Push 分支。
|
||||||
5. 创建新的pull request。
|
5. 创建新的 pull request。
|
||||||
|
|||||||
58
compare/compare.go
Normal file
58
compare/compare.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package compare provides a lightweight comparison function on interface{} type.
|
||||||
|
// reference: https://github.com/stretchr/testify
|
||||||
|
package compare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// operator type
|
||||||
|
const (
|
||||||
|
equal = "eq"
|
||||||
|
lessThan = "lt"
|
||||||
|
greaterThan = "gt"
|
||||||
|
lessOrEqual = "le"
|
||||||
|
greaterOrEqual = "ge"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
timeType = reflect.TypeOf(time.Time{})
|
||||||
|
bytesType = reflect.TypeOf([]byte{})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Equal checks if two values are equal or not. (check both type and value)
|
||||||
|
func Equal(left, right interface{}) bool {
|
||||||
|
return compareValue(equal, left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EqualValue checks if two values are equal or not. (check value only)
|
||||||
|
func EqualValue(left, right interface{}) bool {
|
||||||
|
ls, rs := convertor.ToString(left), convertor.ToString(right)
|
||||||
|
return ls == rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessThan checks if value `left` less than value `right`.
|
||||||
|
func LessThan(left, right interface{}) bool {
|
||||||
|
return compareValue(lessThan, left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterThan checks if value `left` greater than value `right`.
|
||||||
|
func GreaterThan(left, right interface{}) bool {
|
||||||
|
return compareValue(greaterThan, left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqual checks if value `left` less than or equal to value `right`.
|
||||||
|
func LessOrEqual(left, right interface{}) bool {
|
||||||
|
return compareValue(lessOrEqual, left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqual checks if value `left` greater than or equal to value `right`.
|
||||||
|
func GreaterOrEqual(left, right interface{}) bool {
|
||||||
|
return compareValue(greaterOrEqual, left, right)
|
||||||
|
}
|
||||||
170
compare/compare_example_test.go
Normal file
170
compare/compare_example_test.go
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
package compare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleEqual() {
|
||||||
|
result1 := Equal(1, 1)
|
||||||
|
result2 := Equal("1", "1")
|
||||||
|
result3 := Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||||
|
result4 := Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||||
|
|
||||||
|
result5 := Equal(1, "1")
|
||||||
|
result6 := Equal(1, int64(1))
|
||||||
|
result7 := Equal([]int{1, 2}, []int{1, 2, 3})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEqualValue() {
|
||||||
|
result1 := EqualValue(1, 1)
|
||||||
|
result2 := EqualValue(int(1), int64(1))
|
||||||
|
result3 := EqualValue(1, "1")
|
||||||
|
result4 := EqualValue(1, "2")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleLessThan() {
|
||||||
|
result1 := LessThan(1, 2)
|
||||||
|
result2 := LessThan(1.1, 2.2)
|
||||||
|
result3 := LessThan("a", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := LessThan(time1, time2)
|
||||||
|
|
||||||
|
result5 := LessThan(2, 1)
|
||||||
|
result6 := LessThan(1, int64(2))
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleGreaterThan() {
|
||||||
|
result1 := GreaterThan(2, 1)
|
||||||
|
result2 := GreaterThan(2.2, 1.1)
|
||||||
|
result3 := GreaterThan("b", "a")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := GreaterThan(time2, time1)
|
||||||
|
|
||||||
|
result5 := GreaterThan(1, 2)
|
||||||
|
result6 := GreaterThan(int64(2), 1)
|
||||||
|
result7 := GreaterThan("b", "c")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleLessOrEqual() {
|
||||||
|
result1 := LessOrEqual(1, 1)
|
||||||
|
result2 := LessOrEqual(1.1, 2.2)
|
||||||
|
result3 := LessOrEqual("a", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := LessOrEqual(time1, time2)
|
||||||
|
|
||||||
|
result5 := LessOrEqual(2, 1)
|
||||||
|
result6 := LessOrEqual(1, int64(2))
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleGreaterOrEqual() {
|
||||||
|
result1 := GreaterOrEqual(1, 1)
|
||||||
|
result2 := GreaterOrEqual(2.2, 1.1)
|
||||||
|
result3 := GreaterOrEqual("b", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := GreaterOrEqual(time2, time1)
|
||||||
|
|
||||||
|
result5 := GreaterOrEqual(1, 2)
|
||||||
|
result6 := GreaterOrEqual(int64(2), 1)
|
||||||
|
result7 := GreaterOrEqual("b", "c")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
323
compare/compare_internal.go
Normal file
323
compare/compare_internal.go
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
package compare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func compareValue(operator string, left, right interface{}) bool {
|
||||||
|
leftType, rightType := reflect.TypeOf(left), reflect.TypeOf(right)
|
||||||
|
|
||||||
|
if leftType.Kind() != rightType.Kind() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch leftType.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
|
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
|
||||||
|
return compareBasicValue(operator, left, right)
|
||||||
|
|
||||||
|
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||||
|
return compareRefValue(operator, left, right, leftType.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareRefValue(operator string, leftObj, rightObj interface{}, kind reflect.Kind) bool {
|
||||||
|
leftVal, rightVal := reflect.ValueOf(leftObj), reflect.ValueOf(rightObj)
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Struct:
|
||||||
|
|
||||||
|
// compare time
|
||||||
|
if leftVal.CanConvert(timeType) {
|
||||||
|
timeObj1, ok := leftObj.(time.Time)
|
||||||
|
if !ok {
|
||||||
|
timeObj1 = leftVal.Convert(timeType).Interface().(time.Time)
|
||||||
|
}
|
||||||
|
|
||||||
|
timeObj2, ok := rightObj.(time.Time)
|
||||||
|
if !ok {
|
||||||
|
timeObj2 = rightVal.Convert(timeType).Interface().(time.Time)
|
||||||
|
}
|
||||||
|
|
||||||
|
return compareBasicValue(operator, timeObj1.UnixNano(), timeObj2.UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
// for other struct type, only process equal operator
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
return objectsAreEqualValues(leftObj, rightObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
// compare []byte
|
||||||
|
if leftVal.CanConvert(bytesType) {
|
||||||
|
bytesObj1, ok := leftObj.([]byte)
|
||||||
|
if !ok {
|
||||||
|
bytesObj1 = leftVal.Convert(bytesType).Interface().([]byte)
|
||||||
|
}
|
||||||
|
bytesObj2, ok := rightObj.([]byte)
|
||||||
|
if !ok {
|
||||||
|
bytesObj2 = rightVal.Convert(bytesType).Interface().([]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessThan:
|
||||||
|
if bytes.Compare(bytesObj1, bytesObj2) == -1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterThan:
|
||||||
|
if bytes.Compare(bytesObj1, bytesObj2) == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessOrEqual:
|
||||||
|
if bytes.Compare(bytesObj1, bytesObj2) <= 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterOrEqual:
|
||||||
|
if bytes.Compare(bytesObj1, bytesObj2) >= 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// for other type slice, only process equal operator
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
return reflect.DeepEqual(leftObj, rightObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// only process equal operator
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
return reflect.DeepEqual(leftObj, rightObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func objectsAreEqualValues(expected, actual interface{}) bool {
|
||||||
|
if objectsAreEqual(expected, actual) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
actualType := reflect.TypeOf(actual)
|
||||||
|
if actualType == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
expectedValue := reflect.ValueOf(expected)
|
||||||
|
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
|
||||||
|
// Attempt comparison after type conversion
|
||||||
|
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func objectsAreEqual(expected, actual interface{}) bool {
|
||||||
|
if expected == nil || actual == nil {
|
||||||
|
return expected == actual
|
||||||
|
}
|
||||||
|
|
||||||
|
exp, ok := expected.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return reflect.DeepEqual(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
act, ok := actual.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if exp == nil || act == nil {
|
||||||
|
return exp == nil && act == nil
|
||||||
|
}
|
||||||
|
return bytes.Equal(exp, act)
|
||||||
|
}
|
||||||
|
|
||||||
|
// compareBasic compare basic value: integer, float, string, bool
|
||||||
|
func compareBasicValue(operator string, leftValue, rightValue interface{}) bool {
|
||||||
|
if leftValue == nil && rightValue == nil && operator == equal {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch leftVal := leftValue.(type) {
|
||||||
|
case json.Number:
|
||||||
|
if left, err := leftVal.Float64(); err == nil {
|
||||||
|
switch rightVal := rightValue.(type) {
|
||||||
|
case json.Number:
|
||||||
|
if right, err := rightVal.Float64(); err == nil {
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
if left == right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessThan:
|
||||||
|
if left < right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterThan:
|
||||||
|
if left > right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessOrEqual:
|
||||||
|
if left <= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterOrEqual:
|
||||||
|
if left >= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||||
|
right, err := convertor.ToFloat(rightValue)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
if left == right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessThan:
|
||||||
|
if left < right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterThan:
|
||||||
|
if left > right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessOrEqual:
|
||||||
|
if left <= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterOrEqual:
|
||||||
|
if left >= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||||
|
left, err := convertor.ToFloat(leftValue)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch rightVal := rightValue.(type) {
|
||||||
|
case json.Number:
|
||||||
|
if right, err := rightVal.Float64(); err == nil {
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
if left == right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessThan:
|
||||||
|
if left < right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterThan:
|
||||||
|
if left > right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessOrEqual:
|
||||||
|
if left <= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterOrEqual:
|
||||||
|
if left >= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||||
|
right, err := convertor.ToFloat(rightValue)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
if left == right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessThan:
|
||||||
|
if left < right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterThan:
|
||||||
|
if left > right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessOrEqual:
|
||||||
|
if left <= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterOrEqual:
|
||||||
|
if left >= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case string:
|
||||||
|
left := leftVal
|
||||||
|
switch right := rightValue.(type) {
|
||||||
|
case string:
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
if left == right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessThan:
|
||||||
|
if left < right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterThan:
|
||||||
|
if left > right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case lessOrEqual:
|
||||||
|
if left <= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case greaterOrEqual:
|
||||||
|
if left >= right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case bool:
|
||||||
|
left := leftVal
|
||||||
|
switch right := rightValue.(type) {
|
||||||
|
case bool:
|
||||||
|
switch operator {
|
||||||
|
case equal:
|
||||||
|
if left == right {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
134
compare/compare_test.go
Normal file
134
compare/compare_test.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package compare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEqual(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestEqual")
|
||||||
|
|
||||||
|
assert.Equal(true, Equal(1, 1))
|
||||||
|
assert.Equal(true, Equal(int64(1), int64(1)))
|
||||||
|
assert.Equal(true, Equal("a", "a"))
|
||||||
|
assert.Equal(true, Equal(true, true))
|
||||||
|
assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3}))
|
||||||
|
assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}))
|
||||||
|
|
||||||
|
assert.Equal(false, Equal(1, 2))
|
||||||
|
assert.Equal(false, Equal(1, int64(1)))
|
||||||
|
assert.Equal(false, Equal("a", "b"))
|
||||||
|
assert.Equal(false, Equal(true, false))
|
||||||
|
assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3}))
|
||||||
|
assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}))
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
time3 := time1.Add(time.Second)
|
||||||
|
|
||||||
|
assert.Equal(false, Equal(time1, time2))
|
||||||
|
assert.Equal(true, Equal(time2, time3))
|
||||||
|
|
||||||
|
st1 := struct {
|
||||||
|
A string
|
||||||
|
B string
|
||||||
|
}{
|
||||||
|
A: "a",
|
||||||
|
B: "b",
|
||||||
|
}
|
||||||
|
|
||||||
|
st2 := struct {
|
||||||
|
A string
|
||||||
|
B string
|
||||||
|
}{
|
||||||
|
A: "a",
|
||||||
|
B: "b",
|
||||||
|
}
|
||||||
|
|
||||||
|
st3 := struct {
|
||||||
|
A string
|
||||||
|
B string
|
||||||
|
}{
|
||||||
|
A: "a1",
|
||||||
|
B: "b",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(true, Equal(st1, st2))
|
||||||
|
assert.Equal(false, Equal(st1, st3))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEqualValue(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestEqualValue")
|
||||||
|
|
||||||
|
assert.Equal(true, EqualValue(1, 1))
|
||||||
|
assert.Equal(true, EqualValue(int(1), int64(1)))
|
||||||
|
assert.Equal(true, EqualValue(1, "1"))
|
||||||
|
|
||||||
|
assert.Equal(false, EqualValue(1, "2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLessThan(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestLessThan")
|
||||||
|
|
||||||
|
assert.Equal(true, LessThan(1, 2))
|
||||||
|
assert.Equal(true, LessThan(1.1, 2.2))
|
||||||
|
assert.Equal(true, LessThan("a", "b"))
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
assert.Equal(true, LessThan(time1, time2))
|
||||||
|
|
||||||
|
assert.Equal(false, LessThan(1, 1))
|
||||||
|
assert.Equal(false, LessThan(1, int64(1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGreaterThan(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||||
|
|
||||||
|
assert.Equal(true, GreaterThan(2, 1))
|
||||||
|
assert.Equal(true, GreaterThan(2.2, 1.1))
|
||||||
|
assert.Equal(true, GreaterThan("b", "a"))
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
assert.Equal(true, GreaterThan(time2, time1))
|
||||||
|
|
||||||
|
assert.Equal(false, GreaterThan(1, 2))
|
||||||
|
assert.Equal(false, GreaterThan(int64(2), 1))
|
||||||
|
assert.Equal(false, GreaterThan("b", "c"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLessOrEqual(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestLessOrEqual")
|
||||||
|
|
||||||
|
assert.Equal(true, LessOrEqual(1, 2))
|
||||||
|
assert.Equal(true, LessOrEqual(1, 1))
|
||||||
|
assert.Equal(true, LessOrEqual(1.1, 2.2))
|
||||||
|
assert.Equal(true, LessOrEqual("a", "b"))
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
assert.Equal(true, LessOrEqual(time1, time2))
|
||||||
|
|
||||||
|
assert.Equal(false, LessOrEqual(2, 1))
|
||||||
|
assert.Equal(false, LessOrEqual(1, int64(2)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGreaterOrEqual(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||||
|
|
||||||
|
assert.Equal(true, GreaterOrEqual(2, 1))
|
||||||
|
assert.Equal(true, GreaterOrEqual(1, 1))
|
||||||
|
assert.Equal(true, GreaterOrEqual(2.2, 1.1))
|
||||||
|
assert.Equal(true, GreaterOrEqual("b", "b"))
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
assert.Equal(true, GreaterOrEqual(time2, time1))
|
||||||
|
|
||||||
|
assert.Equal(false, GreaterOrEqual(1, 2))
|
||||||
|
assert.Equal(false, GreaterOrEqual(int64(2), 1))
|
||||||
|
assert.Equal(false, GreaterOrEqual("b", "c"))
|
||||||
|
}
|
||||||
@@ -6,13 +6,20 @@ package convertor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
|
"golang.org/x/text/transform"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToBool convert string to a boolean
|
// ToBool convert string to a boolean
|
||||||
@@ -21,14 +28,44 @@ func ToBool(s string) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ToBytes convert interface to bytes
|
// ToBytes convert interface to bytes
|
||||||
func ToBytes(data interface{}) ([]byte, error) {
|
func ToBytes(value interface{}) ([]byte, error) {
|
||||||
var buf bytes.Buffer
|
v := reflect.ValueOf(value)
|
||||||
enc := gob.NewEncoder(&buf)
|
|
||||||
err := enc.Encode(data)
|
switch value.(type) {
|
||||||
if err != nil {
|
case int, int8, int16, int32, int64:
|
||||||
return nil, err
|
number := v.Int()
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
buf.Reset()
|
||||||
|
err := binary.Write(buf, binary.BigEndian, number)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
case uint, uint8, uint16, uint32, uint64:
|
||||||
|
number := v.Uint()
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
buf.Reset()
|
||||||
|
err := binary.Write(buf, binary.BigEndian, number)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
case float32:
|
||||||
|
number := float32(v.Float())
|
||||||
|
bits := math.Float32bits(number)
|
||||||
|
bytes := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(bytes, bits)
|
||||||
|
return bytes, nil
|
||||||
|
case float64:
|
||||||
|
number := v.Float()
|
||||||
|
bits := math.Float64bits(number)
|
||||||
|
bytes := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(bytes, bits)
|
||||||
|
return bytes, nil
|
||||||
|
case bool:
|
||||||
|
return strconv.AppendBool([]byte{}, v.Bool()), nil
|
||||||
|
case string:
|
||||||
|
return []byte(v.String()), nil
|
||||||
|
case []byte:
|
||||||
|
return v.Bytes(), nil
|
||||||
|
default:
|
||||||
|
newValue, err := json.Marshal(value)
|
||||||
|
return newValue, err
|
||||||
}
|
}
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToChar convert string to char slice
|
// ToChar convert string to char slice
|
||||||
@@ -45,33 +82,45 @@ func ToChar(s string) []string {
|
|||||||
|
|
||||||
// ToString convert value to string
|
// ToString convert value to string
|
||||||
func ToString(value interface{}) string {
|
func ToString(value interface{}) string {
|
||||||
res := ""
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return res
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
v := reflect.ValueOf(value)
|
switch val := value.(type) {
|
||||||
|
case float32:
|
||||||
switch value.(type) {
|
return strconv.FormatFloat(float64(val), 'f', -1, 32)
|
||||||
case float32, float64:
|
case float64:
|
||||||
res = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
return strconv.FormatFloat(val, 'f', -1, 64)
|
||||||
return res
|
case int:
|
||||||
case int, int8, int16, int32, int64:
|
return strconv.FormatInt(int64(val), 10)
|
||||||
res = strconv.FormatInt(v.Int(), 10)
|
case int8:
|
||||||
return res
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case uint, uint8, uint16, uint32, uint64:
|
case int16:
|
||||||
res = strconv.FormatUint(v.Uint(), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
return res
|
case int32:
|
||||||
|
return strconv.FormatInt(int64(val), 10)
|
||||||
|
case int64:
|
||||||
|
return strconv.FormatInt(val, 10)
|
||||||
|
case uint:
|
||||||
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
|
case uint8:
|
||||||
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
|
case uint16:
|
||||||
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
|
case uint32:
|
||||||
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
|
case uint64:
|
||||||
|
return strconv.FormatUint(val, 10)
|
||||||
case string:
|
case string:
|
||||||
res = v.String()
|
return val
|
||||||
return res
|
|
||||||
case []byte:
|
case []byte:
|
||||||
res = string(v.Bytes())
|
return string(val)
|
||||||
return res
|
|
||||||
default:
|
default:
|
||||||
newValue, _ := json.Marshal(value)
|
b, err := json.Marshal(val)
|
||||||
res = string(newValue)
|
if err != nil {
|
||||||
return res
|
return ""
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,3 +247,160 @@ func ColorRGBToHex(red, green, blue int) string {
|
|||||||
|
|
||||||
return "#" + r + g + b
|
return "#" + r + g + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToChannel convert a array of elements to a read-only channels
|
||||||
|
func ToChannel(array []interface{}) <-chan interface{} {
|
||||||
|
ch := make(chan interface{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, item := range array {
|
||||||
|
ch <- item
|
||||||
|
}
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeByte encode data to byte
|
||||||
|
func EncodeByte(data interface{}) ([]byte, error) {
|
||||||
|
buffer := bytes.NewBuffer(nil)
|
||||||
|
encoder := gob.NewEncoder(buffer)
|
||||||
|
err := encoder.Encode(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeByte decode byte data to target object
|
||||||
|
func DecodeByte(data []byte, target interface{}) error {
|
||||||
|
buffer := bytes.NewBuffer(data)
|
||||||
|
decoder := gob.NewDecoder(buffer)
|
||||||
|
return decoder.Decode(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepClone creates a deep copy of passed item.
|
||||||
|
// can't clone unexported field of struct
|
||||||
|
func DeepClone(src interface{}) interface{} {
|
||||||
|
c := cloner{
|
||||||
|
ptrs: map[reflect.Type]map[uintptr]reflect.Value{},
|
||||||
|
}
|
||||||
|
result := c.clone(reflect.ValueOf(src))
|
||||||
|
if result.Kind() == reflect.Invalid {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// // CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||||
|
// func CopyProperties(dst, src interface{}) (err error) {
|
||||||
|
// defer func() {
|
||||||
|
// if e := recover(); e != nil {
|
||||||
|
// err = errors.New(fmt.Sprintf("%v", e))
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
|
||||||
|
// dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
|
||||||
|
// srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
|
||||||
|
|
||||||
|
// if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
||||||
|
// return errors.New("CopyProperties: param dst should be struct pointer")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if srcType.Kind() == reflect.Ptr {
|
||||||
|
// srcType, srcValue = srcType.Elem(), srcValue.Elem()
|
||||||
|
// }
|
||||||
|
// if srcType.Kind() != reflect.Struct {
|
||||||
|
// return errors.New("CopyProperties: param src should be a struct or struct pointer")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// dstType, dstValue = dstType.Elem(), dstValue.Elem()
|
||||||
|
|
||||||
|
// propertyNums := dstType.NumField()
|
||||||
|
|
||||||
|
// for i := 0; i < propertyNums; i++ {
|
||||||
|
// property := dstType.Field(i)
|
||||||
|
// propertyValue := srcValue.FieldByName(property.Name)
|
||||||
|
|
||||||
|
// if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if dstValue.Field(i).CanSet() {
|
||||||
|
// dstValue.Field(i).Set(propertyValue)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||||
|
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
|
||||||
|
func CopyProperties(dst, src interface{}) error {
|
||||||
|
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
|
||||||
|
|
||||||
|
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
||||||
|
return errors.New("CopyProperties: parameter dst should be struct pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcType.Kind() == reflect.Ptr {
|
||||||
|
srcType = srcType.Elem()
|
||||||
|
}
|
||||||
|
if srcType.Kind() != reflect.Struct {
|
||||||
|
return errors.New("CopyProperties: parameter src should be a struct or struct pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(bytes, dst)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToInterface converts reflect value to its interface type.
|
||||||
|
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
|
||||||
|
if v.IsValid() && v.CanInterface() {
|
||||||
|
return v.Interface(), true
|
||||||
|
}
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return v.Bool(), true
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int(), true
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return v.Uint(), true
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float(), true
|
||||||
|
case reflect.Complex64, reflect.Complex128:
|
||||||
|
return v.Complex(), true
|
||||||
|
case reflect.String:
|
||||||
|
return v.String(), true
|
||||||
|
case reflect.Ptr:
|
||||||
|
return ToInterface(v.Elem())
|
||||||
|
case reflect.Interface:
|
||||||
|
return ToInterface(v.Elem())
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utf8ToGbk convert utf8 encoding data to GBK encoding data.
|
||||||
|
func Utf8ToGbk(bs []byte) ([]byte, error) {
|
||||||
|
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
|
||||||
|
b, err := io.ReadAll(r)
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GbkToUtf8 convert GBK encoding data to utf8 encoding data.
|
||||||
|
func GbkToUtf8(bs []byte) ([]byte, error) {
|
||||||
|
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
|
||||||
|
b, err := io.ReadAll(r)
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|||||||
216
convertor/convertor_internal.go
Normal file
216
convertor/convertor_internal.go
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package convertor implements some functions to convert data.
|
||||||
|
package convertor
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
type cloner struct {
|
||||||
|
ptrs map[reflect.Type]map[uintptr]reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone return a duplicate of passed item.
|
||||||
|
func (c *cloner) clone(v reflect.Value) reflect.Value {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Invalid:
|
||||||
|
return reflect.ValueOf(nil)
|
||||||
|
|
||||||
|
// bool
|
||||||
|
case reflect.Bool:
|
||||||
|
return reflect.ValueOf(v.Bool())
|
||||||
|
|
||||||
|
//int
|
||||||
|
case reflect.Int:
|
||||||
|
return reflect.ValueOf(int(v.Int()))
|
||||||
|
case reflect.Int8:
|
||||||
|
return reflect.ValueOf(int8(v.Int()))
|
||||||
|
case reflect.Int16:
|
||||||
|
return reflect.ValueOf(int16(v.Int()))
|
||||||
|
case reflect.Int32:
|
||||||
|
return reflect.ValueOf(int32(v.Int()))
|
||||||
|
case reflect.Int64:
|
||||||
|
return reflect.ValueOf(v.Int())
|
||||||
|
|
||||||
|
// uint
|
||||||
|
case reflect.Uint:
|
||||||
|
return reflect.ValueOf(uint(v.Uint()))
|
||||||
|
case reflect.Uint8:
|
||||||
|
return reflect.ValueOf(uint8(v.Uint()))
|
||||||
|
case reflect.Uint16:
|
||||||
|
return reflect.ValueOf(uint16(v.Uint()))
|
||||||
|
case reflect.Uint32:
|
||||||
|
return reflect.ValueOf(uint32(v.Uint()))
|
||||||
|
case reflect.Uint64:
|
||||||
|
return reflect.ValueOf(v.Uint())
|
||||||
|
|
||||||
|
// float
|
||||||
|
case reflect.Float32:
|
||||||
|
return reflect.ValueOf(float32(v.Float()))
|
||||||
|
case reflect.Float64:
|
||||||
|
return reflect.ValueOf(v.Float())
|
||||||
|
|
||||||
|
// complex
|
||||||
|
case reflect.Complex64:
|
||||||
|
return reflect.ValueOf(complex64(v.Complex()))
|
||||||
|
case reflect.Complex128:
|
||||||
|
return reflect.ValueOf(v.Complex())
|
||||||
|
|
||||||
|
// string
|
||||||
|
case reflect.String:
|
||||||
|
return reflect.ValueOf(v.String())
|
||||||
|
|
||||||
|
// array
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
return c.cloneArray(v)
|
||||||
|
|
||||||
|
// map
|
||||||
|
case reflect.Map:
|
||||||
|
return c.cloneMap(v)
|
||||||
|
|
||||||
|
// Ptr
|
||||||
|
case reflect.Ptr:
|
||||||
|
return c.clonePtr(v)
|
||||||
|
|
||||||
|
// struct
|
||||||
|
case reflect.Struct:
|
||||||
|
return c.cloneStruct(v)
|
||||||
|
|
||||||
|
// func
|
||||||
|
case reflect.Func:
|
||||||
|
return v
|
||||||
|
|
||||||
|
// interface
|
||||||
|
case reflect.Interface:
|
||||||
|
return c.clone(v.Elem())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.Zero(v.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cloner) cloneArray(v reflect.Value) reflect.Value {
|
||||||
|
if v.IsNil() {
|
||||||
|
return reflect.Zero(v.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
|
||||||
|
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
val := c.clone(v.Index(i))
|
||||||
|
|
||||||
|
if val.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
item := arr.Index(i)
|
||||||
|
if !item.CanSet() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
item.Set(val.Convert(item.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cloner) cloneMap(v reflect.Value) reflect.Value {
|
||||||
|
if v.IsNil() {
|
||||||
|
return reflect.Zero(v.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
clonedMap := reflect.MakeMap(v.Type())
|
||||||
|
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
value := v.MapIndex(key)
|
||||||
|
clonedKey := c.clone(key)
|
||||||
|
clonedValue := c.clone(value)
|
||||||
|
|
||||||
|
if !isNillable(clonedKey) || !clonedKey.IsNil() {
|
||||||
|
clonedKey = clonedKey.Convert(key.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNillable(clonedValue) || !clonedValue.IsNil()) && clonedValue.IsValid() {
|
||||||
|
clonedValue = clonedValue.Convert(value.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !clonedValue.IsValid() {
|
||||||
|
clonedValue = reflect.Zero(clonedMap.Type().Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
clonedMap.SetMapIndex(clonedKey, clonedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return clonedMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNillable(v reflect.Value) bool {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Chan, reflect.Interface, reflect.Ptr, reflect.Func:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cloner) clonePtr(v reflect.Value) reflect.Value {
|
||||||
|
if v.IsNil() {
|
||||||
|
return reflect.Zero(v.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
var newVal reflect.Value
|
||||||
|
|
||||||
|
if v.Elem().CanAddr() {
|
||||||
|
ptrs, exists := c.ptrs[v.Type()]
|
||||||
|
if exists {
|
||||||
|
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
|
||||||
|
return newVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newVal = c.clone(v.Elem())
|
||||||
|
|
||||||
|
if v.Elem().CanAddr() {
|
||||||
|
ptrs, exists := c.ptrs[v.Type()]
|
||||||
|
if exists {
|
||||||
|
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
|
||||||
|
return newVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clonedPtr := reflect.New(newVal.Type())
|
||||||
|
clonedPtr.Elem().Set(newVal)
|
||||||
|
|
||||||
|
return clonedPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cloner) cloneStruct(v reflect.Value) reflect.Value {
|
||||||
|
clonedStructPtr := reflect.New(v.Type())
|
||||||
|
clonedStruct := clonedStructPtr.Elem()
|
||||||
|
|
||||||
|
if v.CanAddr() {
|
||||||
|
ptrs := c.ptrs[clonedStructPtr.Type()]
|
||||||
|
if ptrs == nil {
|
||||||
|
ptrs = make(map[uintptr]reflect.Value)
|
||||||
|
c.ptrs[clonedStructPtr.Type()] = ptrs
|
||||||
|
}
|
||||||
|
ptrs[v.UnsafeAddr()] = clonedStructPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
newStructValue := clonedStruct.Field(i)
|
||||||
|
if !newStructValue.CanSet() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
clonedVal := c.clone(v.Field(i))
|
||||||
|
if !clonedVal.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newStructValue.Set(clonedVal.Convert(newStructValue.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return clonedStruct
|
||||||
|
}
|
||||||
@@ -2,9 +2,12 @@ package convertor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
"github.com/duke-git/lancet/internal"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestToChar(t *testing.T) {
|
func TestToChar(t *testing.T) {
|
||||||
@@ -42,14 +45,21 @@ func TestToBytes(t *testing.T) {
|
|||||||
"1",
|
"1",
|
||||||
}
|
}
|
||||||
expected := [][]byte{
|
expected := [][]byte{
|
||||||
{3, 4, 0, 0},
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
{3, 2, 0, 0},
|
{102, 97, 108, 115, 101},
|
||||||
{4, 12, 0, 1, 49},
|
{49},
|
||||||
}
|
}
|
||||||
for i := 0; i < len(cases); i++ {
|
for i := 0; i < len(cases); i++ {
|
||||||
actual, _ := ToBytes(cases[i])
|
actual, _ := ToBytes(cases[i])
|
||||||
assert.Equal(expected[i], actual)
|
assert.Equal(expected[i], actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytesData, err := ToBytes("abc")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
assert.Equal("abc", ToString(bytesData))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToInt(t *testing.T) {
|
func TestToInt(t *testing.T) {
|
||||||
@@ -111,7 +121,7 @@ func TestToString(t *testing.T) {
|
|||||||
"", "",
|
"", "",
|
||||||
"0", "1", "-1",
|
"0", "1", "-1",
|
||||||
"123", "123", "123", "123", "123", "123", "123",
|
"123", "123", "123", "123", "123", "123", "123",
|
||||||
"12.3", "12.300000190734863",
|
"12.3", "12.3",
|
||||||
"true", "false",
|
"true", "false",
|
||||||
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
|
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
|
||||||
|
|
||||||
@@ -171,3 +181,185 @@ func TestColorRGBToHex(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestColorRGBToHex")
|
assert := internal.NewAssert(t, "TestColorRGBToHex")
|
||||||
assert.Equal(expected, colorHex)
|
assert.Equal(expected, colorHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToChannel(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToChannel")
|
||||||
|
|
||||||
|
ch := ToChannel([]interface{}{1, 2, 3})
|
||||||
|
val1, _ := <-ch
|
||||||
|
assert.Equal(1, val1)
|
||||||
|
|
||||||
|
val2, _ := <-ch
|
||||||
|
assert.Equal(2, val2)
|
||||||
|
|
||||||
|
val3, _ := <-ch
|
||||||
|
assert.Equal(3, val3)
|
||||||
|
|
||||||
|
_, ok := <-ch
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeByte(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestEncodeByte")
|
||||||
|
|
||||||
|
byteData, _ := EncodeByte("abc")
|
||||||
|
expected := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
|
|
||||||
|
assert.Equal(expected, byteData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeByte(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDecodeByte")
|
||||||
|
|
||||||
|
var obj string
|
||||||
|
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
|
DecodeByte(byteData, &obj)
|
||||||
|
assert.Equal("abc", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeepClone(t *testing.T) {
|
||||||
|
// assert := internal.NewAssert(t, "TestDeepClone")
|
||||||
|
|
||||||
|
type Struct struct {
|
||||||
|
Str string
|
||||||
|
Int int
|
||||||
|
Float float64
|
||||||
|
Bool bool
|
||||||
|
Nil interface{}
|
||||||
|
unexported string
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []interface{}{
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
0.1,
|
||||||
|
map[string]int{
|
||||||
|
"a": 1,
|
||||||
|
"b": 2,
|
||||||
|
},
|
||||||
|
&Struct{
|
||||||
|
Str: "test",
|
||||||
|
Int: 1,
|
||||||
|
Float: 0.1,
|
||||||
|
Bool: true,
|
||||||
|
Nil: nil,
|
||||||
|
// unexported: "can't be cloned",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, item := range cases {
|
||||||
|
cloned := DeepClone(item)
|
||||||
|
|
||||||
|
t.Log(cloned)
|
||||||
|
if &cloned == &item {
|
||||||
|
t.Fatalf("[TestDeepClone case #%d failed]: equal pointer", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(item, cloned) {
|
||||||
|
t.Fatalf("[TestDeepClone case #%d failed] unequal objects", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyProperties(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestCopyProperties")
|
||||||
|
|
||||||
|
type Disk struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiskVO struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Indicator struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int `json:"cpu"`
|
||||||
|
Disk []Disk `json:"disk"`
|
||||||
|
Stop chan bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IndicatorVO struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int64 `json:"cpu"`
|
||||||
|
Disk []DiskVO `json:"disk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||||
|
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||||
|
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||||
|
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||||
|
}}
|
||||||
|
|
||||||
|
indicatorVO := IndicatorVO{}
|
||||||
|
|
||||||
|
err := CopyProperties(&indicatorVO, indicator)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("001", indicatorVO.Id)
|
||||||
|
assert.Equal("127.0.0.1", indicatorVO.Ip)
|
||||||
|
assert.Equal(3, len(indicatorVO.Disk))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToInterface(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToInterface")
|
||||||
|
|
||||||
|
cases := []reflect.Value{
|
||||||
|
reflect.ValueOf("abc"),
|
||||||
|
reflect.ValueOf(int(0)), reflect.ValueOf(int8(1)), reflect.ValueOf(int16(-1)), reflect.ValueOf(int32(123)), reflect.ValueOf(int64(123)),
|
||||||
|
reflect.ValueOf(uint(123)), reflect.ValueOf(uint8(123)), reflect.ValueOf(uint16(123)), reflect.ValueOf(uint32(123)), reflect.ValueOf(uint64(123)),
|
||||||
|
reflect.ValueOf(float64(12.3)), reflect.ValueOf(float32(12.3)),
|
||||||
|
reflect.ValueOf(true), reflect.ValueOf(false),
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []interface{}{
|
||||||
|
"abc",
|
||||||
|
0, int8(1), int16(-1), int32(123), int64(123),
|
||||||
|
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||||
|
float64(12.3), float32(12.3),
|
||||||
|
true, false,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(cases); i++ {
|
||||||
|
actual, _ := ToInterface(cases[i])
|
||||||
|
assert.Equal(expected[i], actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
nilVal, ok := ToInterface(reflect.ValueOf(nil))
|
||||||
|
assert.EqualValues(nil, nilVal)
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUtf8ToGbk(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestUtf8ToGbk")
|
||||||
|
|
||||||
|
utf8Data := []byte("hello")
|
||||||
|
gbkData, err := Utf8ToGbk(utf8Data)
|
||||||
|
|
||||||
|
assert.Equal(true, utf8.Valid(utf8Data))
|
||||||
|
assert.Equal(true, validator.IsGBK(gbkData))
|
||||||
|
assert.IsNil(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGbkToUtf8(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestGbkToUtf8")
|
||||||
|
|
||||||
|
gbkData, err := Utf8ToGbk([]byte("hello"))
|
||||||
|
utf8Data, err := GbkToUtf8(gbkData)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(true, utf8.Valid(utf8Data))
|
||||||
|
assert.Equal("hello", string(utf8Data))
|
||||||
|
}
|
||||||
|
|||||||
168
cryptor/aes.go
168
cryptor/aes.go
@@ -1,168 +0,0 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
|
||||||
// Use of this source code is governed by MIT license
|
|
||||||
|
|
||||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
|
||||||
// Note:
|
|
||||||
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
|
|
||||||
package cryptor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesEcbEncrypt(data, key []byte) []byte {
|
|
||||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
|
||||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
|
||||||
plain := make([]byte, length*aes.BlockSize)
|
|
||||||
copy(plain, data)
|
|
||||||
pad := byte(len(plain) - len(data))
|
|
||||||
for i := len(data); i < len(plain); i++ {
|
|
||||||
plain[i] = pad
|
|
||||||
}
|
|
||||||
encrypted := make([]byte, len(plain))
|
|
||||||
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])
|
|
||||||
}
|
|
||||||
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesEcbDecrypt(encrypted, key []byte) []byte {
|
|
||||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
|
||||||
decrypted := make([]byte, len(encrypted))
|
|
||||||
//
|
|
||||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
|
||||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
|
||||||
}
|
|
||||||
|
|
||||||
trim := 0
|
|
||||||
if len(decrypted) > 0 {
|
|
||||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return decrypted[:trim]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesCbcEncrypt(data, key []byte) []byte {
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
blockSize := block.BlockSize()
|
|
||||||
data = pkcs7Padding(data, blockSize)
|
|
||||||
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
|
|
||||||
|
|
||||||
encrypted := make([]byte, len(data))
|
|
||||||
blockMode.CryptBlocks(encrypted, data)
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesCbcDecrypt(encrypted, key []byte) []byte {
|
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
blockSize := block.BlockSize()
|
|
||||||
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
|
|
||||||
|
|
||||||
decrypted := make([]byte, len(encrypted))
|
|
||||||
blockMode.CryptBlocks(decrypted, encrypted)
|
|
||||||
decrypted = pkcs7UnPadding(decrypted)
|
|
||||||
return decrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesCtrCrypt encrypt data with key use AES CTR algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesCtrCrypt(data, key []byte) []byte {
|
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
|
|
||||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
|
||||||
stream := cipher.NewCTR(block, iv)
|
|
||||||
|
|
||||||
dst := make([]byte, len(data))
|
|
||||||
stream.XORKeyStream(dst, data)
|
|
||||||
|
|
||||||
return dst
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesCfbEncrypt(data, key []byte) []byte {
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
|
||||||
iv := encrypted[:aes.BlockSize]
|
|
||||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stream := cipher.NewCFBEncrypter(block, iv)
|
|
||||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
|
||||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
|
||||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
if len(encrypted) < aes.BlockSize {
|
|
||||||
panic("encrypted data is too short")
|
|
||||||
}
|
|
||||||
iv := encrypted[:aes.BlockSize]
|
|
||||||
encrypted = encrypted[aes.BlockSize:]
|
|
||||||
|
|
||||||
stream := cipher.NewCFBDecrypter(block, iv)
|
|
||||||
stream.XORKeyStream(encrypted, encrypted)
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesOfbEncrypt(data, key []byte) []byte {
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
data = pkcs7Padding(data, aes.BlockSize)
|
|
||||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
|
||||||
iv := encrypted[:aes.BlockSize]
|
|
||||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stream := cipher.NewOFB(block, iv)
|
|
||||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func AesOfbDecrypt(data, key []byte) []byte {
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
iv := data[:aes.BlockSize]
|
|
||||||
data = data[aes.BlockSize:]
|
|
||||||
if len(data)%aes.BlockSize != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
decrypted := make([]byte, len(data))
|
|
||||||
mode := cipher.NewOFB(block, iv)
|
|
||||||
mode.XORKeyStream(decrypted, data)
|
|
||||||
|
|
||||||
decrypted = pkcs7UnPadding(decrypted)
|
|
||||||
return decrypted
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package cryptor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAesEcbEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefghijklmnop"
|
|
||||||
|
|
||||||
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
|
|
||||||
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
|
|
||||||
assert.Equal(data, string(aesEcbDecrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAesCbcEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefghijklmnop"
|
|
||||||
|
|
||||||
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
|
|
||||||
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
|
|
||||||
assert.Equal(data, string(aesCbcDecrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAesCtrCrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefghijklmnop"
|
|
||||||
|
|
||||||
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
|
|
||||||
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAesCtrCrypt")
|
|
||||||
assert.Equal(data, string(aesCtrDeCrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAesCfbEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefghijklmnop"
|
|
||||||
|
|
||||||
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
|
|
||||||
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
|
|
||||||
assert.Equal(data, string(aesCfbDecrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAesOfbEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefghijklmnop"
|
|
||||||
|
|
||||||
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
|
|
||||||
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
|
|
||||||
assert.Equal(data, string(aesOfbDecrypt))
|
|
||||||
}
|
|
||||||
@@ -37,6 +37,27 @@ func Md5String(s string) string {
|
|||||||
return hex.EncodeToString(h.Sum(nil))
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Md5StringWithBase64 return the md5 value of string with base64.
|
||||||
|
func Md5StringWithBase64(s string) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(s))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Md5Byte return the md5 string of byte slice.
|
||||||
|
func Md5Byte(data []byte) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(data)
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Md5ByteWithBase64 return the md5 string of byte slice with base64.
|
||||||
|
func Md5ByteWithBase64(data []byte) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(data)
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
// Md5File return the md5 value of file
|
// Md5File return the md5 value of file
|
||||||
func Md5File(filename string) (string, error) {
|
func Md5File(filename string) (string, error) {
|
||||||
if fileInfo, err := os.Stat(filename); err != nil {
|
if fileInfo, err := os.Stat(filename); err != nil {
|
||||||
@@ -76,6 +97,13 @@ func HmacMd5(data, key string) string {
|
|||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
return hex.EncodeToString(h.Sum([]byte("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HmacMd5WithBase64 return the hmac hash of string use md5 with base64.
|
||||||
|
func HmacMd5WithBase64(data, key string) string {
|
||||||
|
h := hmac.New(md5.New, []byte(key))
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||||
|
}
|
||||||
|
|
||||||
// HmacSha1 return the hmac hash of string use sha1
|
// HmacSha1 return the hmac hash of string use sha1
|
||||||
func HmacSha1(data, key string) string {
|
func HmacSha1(data, key string) string {
|
||||||
h := hmac.New(sha1.New, []byte(key))
|
h := hmac.New(sha1.New, []byte(key))
|
||||||
@@ -83,6 +111,13 @@ func HmacSha1(data, key string) string {
|
|||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
return hex.EncodeToString(h.Sum([]byte("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HmacSha1WithBase64 return the hmac hash of string use sha1 with base64.
|
||||||
|
func HmacSha1WithBase64(str, key string) string {
|
||||||
|
h := hmac.New(sha1.New, []byte(key))
|
||||||
|
h.Write([]byte(str))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||||
|
}
|
||||||
|
|
||||||
// HmacSha256 return the hmac hash of string use sha256
|
// HmacSha256 return the hmac hash of string use sha256
|
||||||
func HmacSha256(data, key string) string {
|
func HmacSha256(data, key string) string {
|
||||||
h := hmac.New(sha256.New, []byte(key))
|
h := hmac.New(sha256.New, []byte(key))
|
||||||
@@ -90,6 +125,13 @@ func HmacSha256(data, key string) string {
|
|||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
return hex.EncodeToString(h.Sum([]byte("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HmacSha256WithBase64 return the hmac hash of string use sha256 with base64.
|
||||||
|
func HmacSha256WithBase64(str, key string) string {
|
||||||
|
h := hmac.New(sha256.New, []byte(key))
|
||||||
|
h.Write([]byte(str))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||||
|
}
|
||||||
|
|
||||||
// HmacSha512 return the hmac hash of string use sha512
|
// HmacSha512 return the hmac hash of string use sha512
|
||||||
func HmacSha512(data, key string) string {
|
func HmacSha512(data, key string) string {
|
||||||
h := hmac.New(sha512.New, []byte(key))
|
h := hmac.New(sha512.New, []byte(key))
|
||||||
@@ -97,6 +139,13 @@ func HmacSha512(data, key string) string {
|
|||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
return hex.EncodeToString(h.Sum([]byte("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HmacSha512WithBase64 return the hmac hash of string use sha512 with base64.
|
||||||
|
func HmacSha512WithBase64(str, key string) string {
|
||||||
|
h := hmac.New(sha512.New, []byte(key))
|
||||||
|
h.Write([]byte(str))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||||
|
}
|
||||||
|
|
||||||
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string
|
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string
|
||||||
func Sha1(data string) string {
|
func Sha1(data string) string {
|
||||||
sha1 := sha1.New()
|
sha1 := sha1.New()
|
||||||
@@ -104,6 +153,13 @@ func Sha1(data string) string {
|
|||||||
return hex.EncodeToString(sha1.Sum([]byte("")))
|
return hex.EncodeToString(sha1.Sum([]byte("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sha1WithBase64 return the sha1 value (SHA-1 hash algorithm) of base64 string.
|
||||||
|
func Sha1WithBase64(str string) string {
|
||||||
|
sha1 := sha1.New()
|
||||||
|
sha1.Write([]byte(str))
|
||||||
|
return base64.StdEncoding.EncodeToString(sha1.Sum([]byte("")))
|
||||||
|
}
|
||||||
|
|
||||||
// Sha256 return the sha256 value (SHA256 hash algorithm) of string
|
// Sha256 return the sha256 value (SHA256 hash algorithm) of string
|
||||||
func Sha256(data string) string {
|
func Sha256(data string) string {
|
||||||
sha256 := sha256.New()
|
sha256 := sha256.New()
|
||||||
@@ -111,9 +167,23 @@ func Sha256(data string) string {
|
|||||||
return hex.EncodeToString(sha256.Sum([]byte("")))
|
return hex.EncodeToString(sha256.Sum([]byte("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sha256WithBase64 return the sha256 value (SHA256 hash algorithm) of base64 string.
|
||||||
|
func Sha256WithBase64(str string) string {
|
||||||
|
sha256 := sha256.New()
|
||||||
|
sha256.Write([]byte(str))
|
||||||
|
return base64.StdEncoding.EncodeToString(sha256.Sum([]byte("")))
|
||||||
|
}
|
||||||
|
|
||||||
// Sha512 return the sha512 value (SHA512 hash algorithm) of string
|
// Sha512 return the sha512 value (SHA512 hash algorithm) of string
|
||||||
func Sha512(data string) string {
|
func Sha512(data string) string {
|
||||||
sha512 := sha512.New()
|
sha512 := sha512.New()
|
||||||
sha512.Write([]byte(data))
|
sha512.Write([]byte(data))
|
||||||
return hex.EncodeToString(sha512.Sum([]byte("")))
|
return hex.EncodeToString(sha512.Sum([]byte("")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sha512WithBase64 return the sha512 value (SHA512 hash algorithm) of base64 string.
|
||||||
|
func Sha512WithBase64(str string) string {
|
||||||
|
sha512 := sha512.New()
|
||||||
|
sha512.Write([]byte(str))
|
||||||
|
return base64.StdEncoding.EncodeToString(sha512.Sum([]byte("")))
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,22 @@ func TestMd5String(t *testing.T) {
|
|||||||
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
|
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMd5StringWithBase64(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestMd5StringWithBase64")
|
||||||
|
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5StringWithBase64("hello"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMd5Byte(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestMd5Byte")
|
||||||
|
data := []byte{'a'}
|
||||||
|
assert.Equal("0cc175b9c0f1b6a831c399e269772661", Md5Byte(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMd5ByteWithBase64(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestMd5ByteWithBase64")
|
||||||
|
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5ByteWithBase64([]byte("hello")))
|
||||||
|
}
|
||||||
|
|
||||||
func TestMd5File(t *testing.T) {
|
func TestMd5File(t *testing.T) {
|
||||||
fileMd5, err := Md5File("./basic.go")
|
fileMd5, err := Md5File("./basic.go")
|
||||||
assert := internal.NewAssert(t, "TestMd5File")
|
assert := internal.NewAssert(t, "TestMd5File")
|
||||||
@@ -33,6 +49,11 @@ func TestHmacMd5(t *testing.T) {
|
|||||||
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
|
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHmacMd5WithBase64(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestHmacMd5WithBase64")
|
||||||
|
assert.Equal("6DQwbquJLYclJdSRinpjmg==", HmacMd5WithBase64("hello", "12345"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestHmacSha1(t *testing.T) {
|
func TestHmacSha1(t *testing.T) {
|
||||||
s := "hello world"
|
s := "hello world"
|
||||||
key := "12345"
|
key := "12345"
|
||||||
@@ -43,6 +64,16 @@ func TestHmacSha1(t *testing.T) {
|
|||||||
assert.Equal(expected, hmacSha1)
|
assert.Equal(expected, hmacSha1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHmacSha1WithBase64(t *testing.T) {
|
||||||
|
s := "hello"
|
||||||
|
key := "12345"
|
||||||
|
hmacSha1 := HmacSha1WithBase64(s, key)
|
||||||
|
expected := "XGqdsMzLkuNu0DI/0Jt/k23prOA="
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestHmacSha1")
|
||||||
|
assert.Equal(expected, hmacSha1)
|
||||||
|
}
|
||||||
|
|
||||||
func TestHmacSha256(t *testing.T) {
|
func TestHmacSha256(t *testing.T) {
|
||||||
s := "hello world"
|
s := "hello world"
|
||||||
key := "12345"
|
key := "12345"
|
||||||
@@ -53,6 +84,16 @@ func TestHmacSha256(t *testing.T) {
|
|||||||
assert.Equal(expected, hmacSha256)
|
assert.Equal(expected, hmacSha256)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHmacSha256WithBase64(t *testing.T) {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
hms := HmacSha256WithBase64(str, key)
|
||||||
|
expected := "MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU="
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestHmacSha256WithBase64")
|
||||||
|
assert.Equal(expected, hms)
|
||||||
|
}
|
||||||
|
|
||||||
func TestHmacSha512(t *testing.T) {
|
func TestHmacSha512(t *testing.T) {
|
||||||
s := "hello world"
|
s := "hello world"
|
||||||
key := "12345"
|
key := "12345"
|
||||||
@@ -63,6 +104,16 @@ func TestHmacSha512(t *testing.T) {
|
|||||||
assert.Equal(expected, hmacSha512)
|
assert.Equal(expected, hmacSha512)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHmacSha512WithBase64(t *testing.T) {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
hms := HmacSha512WithBase64(str, key)
|
||||||
|
expected := "3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A=="
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestHmacSha512WithBase64")
|
||||||
|
assert.Equal(expected, hms)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSha1(t *testing.T) {
|
func TestSha1(t *testing.T) {
|
||||||
s := "hello world"
|
s := "hello world"
|
||||||
sha1 := Sha1(s)
|
sha1 := Sha1(s)
|
||||||
@@ -72,6 +123,14 @@ func TestSha1(t *testing.T) {
|
|||||||
assert.Equal(expected, sha1)
|
assert.Equal(expected, sha1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSha1WithBase64(t *testing.T) {
|
||||||
|
str := Sha1WithBase64("hello")
|
||||||
|
expected := "qvTGHdzF6KLavt4PO0gs2a6pQ00="
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestSha1WithBase64")
|
||||||
|
assert.Equal(expected, str)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSha256(t *testing.T) {
|
func TestSha256(t *testing.T) {
|
||||||
s := "hello world"
|
s := "hello world"
|
||||||
sha256 := Sha256(s)
|
sha256 := Sha256(s)
|
||||||
@@ -81,6 +140,14 @@ func TestSha256(t *testing.T) {
|
|||||||
assert.Equal(expected, sha256)
|
assert.Equal(expected, sha256)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSha256WithBase64(t *testing.T) {
|
||||||
|
str := Sha256WithBase64("hello")
|
||||||
|
expected := "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestSha256WithBase64")
|
||||||
|
assert.Equal(expected, str)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSha512(t *testing.T) {
|
func TestSha512(t *testing.T) {
|
||||||
s := "hello world"
|
s := "hello world"
|
||||||
sha512 := Sha512(s)
|
sha512 := Sha512(s)
|
||||||
@@ -89,3 +156,11 @@ func TestSha512(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSha512")
|
assert := internal.NewAssert(t, "TestSha512")
|
||||||
assert.Equal(expected, sha512)
|
assert.Equal(expected, sha512)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSha512WithBase64(t *testing.T) {
|
||||||
|
str := Sha512WithBase64("hello")
|
||||||
|
expected := "m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestSha512WithBase64")
|
||||||
|
assert.Equal(expected, str)
|
||||||
|
}
|
||||||
|
|||||||
490
cryptor/crypto.go
Normal file
490
cryptor/crypto.go
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||||
|
// Note:
|
||||||
|
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
|
||||||
|
package cryptor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesEcbEncrypt(data, key []byte) []byte {
|
||||||
|
size := len(key)
|
||||||
|
if size != 16 && size != 24 && size != 32 {
|
||||||
|
panic("key length shoud be 16 or 24 or 32")
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher, _ := aes.NewCipher(generateAesKey(key, size))
|
||||||
|
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||||
|
|
||||||
|
plain := make([]byte, length*aes.BlockSize)
|
||||||
|
|
||||||
|
copy(plain, data)
|
||||||
|
|
||||||
|
pad := byte(len(plain) - len(data))
|
||||||
|
for i := len(data); i < len(plain); i++ {
|
||||||
|
plain[i] = pad
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted := make([]byte, len(plain))
|
||||||
|
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])
|
||||||
|
}
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesEcbDecrypt(encrypted, key []byte) []byte {
|
||||||
|
size := len(key)
|
||||||
|
if size != 16 && size != 24 && size != 32 {
|
||||||
|
panic("key length shoud be 16 or 24 or 32")
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher, _ := aes.NewCipher(generateAesKey(key, size))
|
||||||
|
decrypted := make([]byte, len(encrypted))
|
||||||
|
|
||||||
|
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||||
|
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||||
|
}
|
||||||
|
|
||||||
|
trim := 0
|
||||||
|
if len(decrypted) > 0 {
|
||||||
|
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return decrypted[:trim]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesCbcEncrypt(data, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
data = pkcs7Padding(data, block.BlockSize())
|
||||||
|
|
||||||
|
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||||
|
iv := encrypted[:aes.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesCbcDecrypt(encrypted, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
|
||||||
|
iv := encrypted[:aes.BlockSize]
|
||||||
|
encrypted = encrypted[aes.BlockSize:]
|
||||||
|
|
||||||
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||||||
|
mode.CryptBlocks(encrypted, encrypted)
|
||||||
|
|
||||||
|
decrypted := pkcs7UnPadding(encrypted)
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesCtrCrypt encrypt data with key use AES CTR algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesCtrCrypt(data, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
|
||||||
|
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||||
|
stream := cipher.NewCTR(block, iv)
|
||||||
|
|
||||||
|
dst := make([]byte, len(data))
|
||||||
|
stream.XORKeyStream(dst, data)
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesCfbEncrypt(data, key []byte) []byte {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||||
|
iv := encrypted[:aes.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := cipher.NewCFBEncrypter(block, iv)
|
||||||
|
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||||
|
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
||||||
|
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
if len(encrypted) < aes.BlockSize {
|
||||||
|
panic("encrypted data is too short")
|
||||||
|
}
|
||||||
|
iv := encrypted[:aes.BlockSize]
|
||||||
|
encrypted = encrypted[aes.BlockSize:]
|
||||||
|
|
||||||
|
stream := cipher.NewCFBDecrypter(block, iv)
|
||||||
|
stream.XORKeyStream(encrypted, encrypted)
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesOfbEncrypt(data, key []byte) []byte {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
data = pkcs7Padding(data, aes.BlockSize)
|
||||||
|
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||||
|
iv := encrypted[:aes.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := cipher.NewOFB(block, iv)
|
||||||
|
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func AesOfbDecrypt(data, key []byte) []byte {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
iv := data[:aes.BlockSize]
|
||||||
|
data = data[aes.BlockSize:]
|
||||||
|
if len(data)%aes.BlockSize != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted := make([]byte, len(data))
|
||||||
|
mode := cipher.NewOFB(block, iv)
|
||||||
|
mode.XORKeyStream(decrypted, data)
|
||||||
|
|
||||||
|
decrypted = pkcs7UnPadding(decrypted)
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||||
|
// len(key) should be 8
|
||||||
|
func DesEcbEncrypt(data, key []byte) []byte {
|
||||||
|
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||||
|
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||||
|
plain := make([]byte, length*des.BlockSize)
|
||||||
|
copy(plain, data)
|
||||||
|
|
||||||
|
pad := byte(len(plain) - len(data))
|
||||||
|
for i := len(data); i < len(plain); i++ {
|
||||||
|
plain[i] = pad
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted := make([]byte, len(plain))
|
||||||
|
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])
|
||||||
|
}
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
|
||||||
|
// len(key) should be 8
|
||||||
|
func DesEcbDecrypt(encrypted, key []byte) []byte {
|
||||||
|
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||||
|
decrypted := make([]byte, len(encrypted))
|
||||||
|
|
||||||
|
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||||
|
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||||
|
}
|
||||||
|
|
||||||
|
trim := 0
|
||||||
|
if len(decrypted) > 0 {
|
||||||
|
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return decrypted[:trim]
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
|
||||||
|
// len(key) should be 8
|
||||||
|
func DesCbcEncrypt(data, key []byte) []byte {
|
||||||
|
block, _ := des.NewCipher(key)
|
||||||
|
data = pkcs7Padding(data, block.BlockSize())
|
||||||
|
|
||||||
|
encrypted := make([]byte, des.BlockSize+len(data))
|
||||||
|
iv := encrypted[:des.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
mode.CryptBlocks(encrypted[des.BlockSize:], data)
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
|
||||||
|
// len(key) should be 8
|
||||||
|
func DesCbcDecrypt(encrypted, key []byte) []byte {
|
||||||
|
block, _ := des.NewCipher(key)
|
||||||
|
|
||||||
|
iv := encrypted[:des.BlockSize]
|
||||||
|
encrypted = encrypted[des.BlockSize:]
|
||||||
|
|
||||||
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||||||
|
mode.CryptBlocks(encrypted, encrypted)
|
||||||
|
|
||||||
|
decrypted := pkcs7UnPadding(encrypted)
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesCtrCrypt encrypt data with key use DES CTR algorithm
|
||||||
|
// len(key) should be 8
|
||||||
|
func DesCtrCrypt(data, key []byte) []byte {
|
||||||
|
block, _ := des.NewCipher(key)
|
||||||
|
|
||||||
|
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||||
|
stream := cipher.NewCTR(block, iv)
|
||||||
|
|
||||||
|
dst := make([]byte, len(data))
|
||||||
|
stream.XORKeyStream(dst, data)
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
|
||||||
|
// len(key) should be 8
|
||||||
|
func DesCfbEncrypt(data, key []byte) []byte {
|
||||||
|
block, err := des.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted := make([]byte, des.BlockSize+len(data))
|
||||||
|
iv := encrypted[:des.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := cipher.NewCFBEncrypter(block, iv)
|
||||||
|
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
|
||||||
|
// len(encrypted) should be great than 16, len(key) should be 8
|
||||||
|
func DesCfbDecrypt(encrypted, key []byte) []byte {
|
||||||
|
block, _ := des.NewCipher(key)
|
||||||
|
if len(encrypted) < des.BlockSize {
|
||||||
|
panic("encrypted data is too short")
|
||||||
|
}
|
||||||
|
iv := encrypted[:des.BlockSize]
|
||||||
|
encrypted = encrypted[des.BlockSize:]
|
||||||
|
|
||||||
|
stream := cipher.NewCFBDecrypter(block, iv)
|
||||||
|
stream.XORKeyStream(encrypted, encrypted)
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
|
||||||
|
// len(key) should be 16, 24 or 32
|
||||||
|
func DesOfbEncrypt(data, key []byte) []byte {
|
||||||
|
block, err := des.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
data = pkcs7Padding(data, des.BlockSize)
|
||||||
|
encrypted := make([]byte, des.BlockSize+len(data))
|
||||||
|
iv := encrypted[:des.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := cipher.NewOFB(block, iv)
|
||||||
|
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
|
||||||
|
// len(key) should be 8
|
||||||
|
func DesOfbDecrypt(data, key []byte) []byte {
|
||||||
|
block, err := des.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
iv := data[:des.BlockSize]
|
||||||
|
data = data[des.BlockSize:]
|
||||||
|
if len(data)%des.BlockSize != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted := make([]byte, len(data))
|
||||||
|
mode := cipher.NewOFB(block, iv)
|
||||||
|
mode.XORKeyStream(decrypted, data)
|
||||||
|
|
||||||
|
decrypted = pkcs7UnPadding(decrypted)
|
||||||
|
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRsaKey make a rsa private key, and return key file name
|
||||||
|
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
|
||||||
|
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||||
|
// private key
|
||||||
|
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
derText := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||||
|
|
||||||
|
block := pem.Block{
|
||||||
|
Type: "rsa private key",
|
||||||
|
Bytes: derText,
|
||||||
|
}
|
||||||
|
|
||||||
|
//file,err := os.Create("rsa_private.pem")
|
||||||
|
file, err := os.Create(priKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pem.Encode(file, &block)
|
||||||
|
file.Close()
|
||||||
|
|
||||||
|
// public key
|
||||||
|
publicKey := privateKey.PublicKey
|
||||||
|
|
||||||
|
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
block = pem.Block{
|
||||||
|
Type: "rsa public key",
|
||||||
|
Bytes: derpText,
|
||||||
|
}
|
||||||
|
|
||||||
|
//file,err = os.Create("rsa_public.pem")
|
||||||
|
file, err = os.Create(pubKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pem.Encode(file, &block)
|
||||||
|
file.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RsaEncrypt encrypt data with ras algorithm
|
||||||
|
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||||
|
file, err := os.Open(pubKeyFileName)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fileInfo, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
buf := make([]byte, fileInfo.Size())
|
||||||
|
file.Read(buf)
|
||||||
|
|
||||||
|
block, _ := pem.Decode(buf)
|
||||||
|
|
||||||
|
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pubKey := pubInterface.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return cipherText
|
||||||
|
}
|
||||||
|
|
||||||
|
// RsaDecrypt decrypt data with ras algorithm
|
||||||
|
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||||
|
file, err := os.Open(privateKeyFileName)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fileInfo, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
buf := make([]byte, fileInfo.Size())
|
||||||
|
defer file.Close()
|
||||||
|
file.Read(buf)
|
||||||
|
|
||||||
|
block, _ := pem.Decode(buf)
|
||||||
|
|
||||||
|
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return plainText
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRsaKeyPair create rsa private and public key.
|
||||||
|
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.
|
||||||
|
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 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return encryptedBytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RsaDecryptOAEP decrypts the data with RSA-OAEP.
|
||||||
|
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 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return decryptedBytes, nil
|
||||||
|
}
|
||||||
@@ -2,15 +2,15 @@ package cryptor
|
|||||||
|
|
||||||
import "bytes"
|
import "bytes"
|
||||||
|
|
||||||
func generateAesKey(key []byte) []byte {
|
func generateAesKey(key []byte, size int) []byte {
|
||||||
genKey := make([]byte, 16)
|
aesKey := make([]byte, size)
|
||||||
copy(genKey, key)
|
copy(aesKey, key)
|
||||||
for i := 16; i < len(key); {
|
for i := size; i < len(key); {
|
||||||
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
|
for j := 0; j < size && i < len(key); j, i = j+1, i+1 {
|
||||||
genKey[j] ^= key[i]
|
aesKey[j] ^= key[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return genKey
|
return aesKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateDesKey(key []byte) []byte {
|
func generateDesKey(key []byte) []byte {
|
||||||
|
|||||||
148
cryptor/crypto_test.go
Normal file
148
cryptor/crypto_test.go
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
package cryptor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAesEcbEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefghijklmnop"
|
||||||
|
|
||||||
|
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
|
||||||
|
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
|
||||||
|
assert.Equal(data, string(aesEcbDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAesCbcEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefghijklmnop"
|
||||||
|
|
||||||
|
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
|
||||||
|
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
|
||||||
|
assert.Equal(data, string(aesCbcDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAesCtrCrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefghijklmnop"
|
||||||
|
|
||||||
|
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
|
||||||
|
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAesCtrCrypt")
|
||||||
|
assert.Equal(data, string(aesCtrDeCrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAesCfbEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefghijklmnop"
|
||||||
|
|
||||||
|
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
|
||||||
|
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
|
||||||
|
assert.Equal(data, string(aesCfbDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAesOfbEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefghijklmnop"
|
||||||
|
|
||||||
|
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
|
||||||
|
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
|
||||||
|
assert.Equal(data, string(aesOfbDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDesEcbEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefgh"
|
||||||
|
|
||||||
|
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
|
||||||
|
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
|
||||||
|
assert.Equal(data, string(desEcbDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDesCbcEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefgh"
|
||||||
|
|
||||||
|
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
|
||||||
|
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
|
||||||
|
assert.Equal(data, string(desCbcDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDesCtrCrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefgh"
|
||||||
|
|
||||||
|
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
|
||||||
|
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestDesCtrCrypt")
|
||||||
|
assert.Equal(data, string(desCtrDeCrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDesCfbEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefgh"
|
||||||
|
|
||||||
|
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
|
||||||
|
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
|
||||||
|
assert.Equal(data, string(desCfbDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDesOfbEncrypt(t *testing.T) {
|
||||||
|
data := "hello world"
|
||||||
|
key := "abcdefgh"
|
||||||
|
|
||||||
|
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
|
||||||
|
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
|
||||||
|
assert.Equal(data, string(desOfbDecrypt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRsaEncrypt(t *testing.T) {
|
||||||
|
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||||
|
if err != nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
data := []byte("hello world")
|
||||||
|
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||||
|
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||||
|
assert.Equal(string(data), string(decrypted))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRsaEncryptOAEP(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
pri, pub := GenerateRsaKeyPair(1024)
|
||||||
|
|
||||||
|
data := []byte("hello world")
|
||||||
|
label := []byte("123456")
|
||||||
|
|
||||||
|
encrypted, err := RsaEncryptOAEP(data, label, *pub)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
decrypted, err := RsaDecryptOAEP([]byte(encrypted), label, *pri)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("hello world", string(decrypted))
|
||||||
|
}
|
||||||
173
cryptor/des.go
173
cryptor/des.go
@@ -1,173 +0,0 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
|
||||||
// Use of this source code is governed by MIT license
|
|
||||||
|
|
||||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
|
||||||
package cryptor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/des"
|
|
||||||
"crypto/rand"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
|
||||||
// len(key) should be 8
|
|
||||||
func DesEcbEncrypt(data, key []byte) []byte {
|
|
||||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
|
||||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
|
||||||
plain := make([]byte, length*des.BlockSize)
|
|
||||||
copy(plain, data)
|
|
||||||
|
|
||||||
pad := byte(len(plain) - len(data))
|
|
||||||
for i := len(data); i < len(plain); i++ {
|
|
||||||
plain[i] = pad
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypted := make([]byte, len(plain))
|
|
||||||
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])
|
|
||||||
}
|
|
||||||
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
|
|
||||||
// len(key) should be 8
|
|
||||||
func DesEcbDecrypt(encrypted, key []byte) []byte {
|
|
||||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
|
||||||
decrypted := make([]byte, len(encrypted))
|
|
||||||
|
|
||||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
|
||||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
|
||||||
}
|
|
||||||
|
|
||||||
trim := 0
|
|
||||||
if len(decrypted) > 0 {
|
|
||||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return decrypted[:trim]
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
|
|
||||||
// len(key) should be 8
|
|
||||||
func DesCbcEncrypt(data, key []byte) []byte {
|
|
||||||
block, _ := des.NewCipher(key)
|
|
||||||
blockSize := block.BlockSize()
|
|
||||||
data = pkcs7Padding(data, blockSize)
|
|
||||||
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
|
|
||||||
|
|
||||||
encrypted := make([]byte, len(data))
|
|
||||||
blockMode.CryptBlocks(encrypted, data)
|
|
||||||
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
|
|
||||||
// len(key) should be 8
|
|
||||||
func DesCbcDecrypt(encrypted, key []byte) []byte {
|
|
||||||
block, _ := des.NewCipher(key)
|
|
||||||
blockSize := block.BlockSize()
|
|
||||||
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
|
|
||||||
|
|
||||||
decrypted := make([]byte, len(encrypted))
|
|
||||||
blockMode.CryptBlocks(decrypted, encrypted)
|
|
||||||
decrypted = pkcs7UnPadding(decrypted)
|
|
||||||
|
|
||||||
return decrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesCtrCrypt encrypt data with key use DES CTR algorithm
|
|
||||||
// len(key) should be 8
|
|
||||||
func DesCtrCrypt(data, key []byte) []byte {
|
|
||||||
block, _ := des.NewCipher(key)
|
|
||||||
|
|
||||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
|
||||||
stream := cipher.NewCTR(block, iv)
|
|
||||||
|
|
||||||
dst := make([]byte, len(data))
|
|
||||||
stream.XORKeyStream(dst, data)
|
|
||||||
|
|
||||||
return dst
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
|
|
||||||
// len(key) should be 8
|
|
||||||
func DesCfbEncrypt(data, key []byte) []byte {
|
|
||||||
block, err := des.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypted := make([]byte, des.BlockSize+len(data))
|
|
||||||
iv := encrypted[:des.BlockSize]
|
|
||||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stream := cipher.NewCFBEncrypter(block, iv)
|
|
||||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
|
||||||
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
|
|
||||||
// len(encrypted) should be great than 16, len(key) should be 8
|
|
||||||
func DesCfbDecrypt(encrypted, key []byte) []byte {
|
|
||||||
block, _ := des.NewCipher(key)
|
|
||||||
if len(encrypted) < des.BlockSize {
|
|
||||||
panic("encrypted data is too short")
|
|
||||||
}
|
|
||||||
iv := encrypted[:des.BlockSize]
|
|
||||||
encrypted = encrypted[des.BlockSize:]
|
|
||||||
|
|
||||||
stream := cipher.NewCFBDecrypter(block, iv)
|
|
||||||
stream.XORKeyStream(encrypted, encrypted)
|
|
||||||
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
|
|
||||||
// len(key) should be 16, 24 or 32
|
|
||||||
func DesOfbEncrypt(data, key []byte) []byte {
|
|
||||||
block, err := des.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
data = pkcs7Padding(data, des.BlockSize)
|
|
||||||
encrypted := make([]byte, des.BlockSize+len(data))
|
|
||||||
iv := encrypted[:des.BlockSize]
|
|
||||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stream := cipher.NewOFB(block, iv)
|
|
||||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
|
||||||
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
|
|
||||||
// len(key) should be 8
|
|
||||||
func DesOfbDecrypt(data, key []byte) []byte {
|
|
||||||
block, err := des.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
iv := data[:des.BlockSize]
|
|
||||||
data = data[des.BlockSize:]
|
|
||||||
if len(data)%des.BlockSize != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
decrypted := make([]byte, len(data))
|
|
||||||
mode := cipher.NewOFB(block, iv)
|
|
||||||
mode.XORKeyStream(decrypted, data)
|
|
||||||
|
|
||||||
decrypted = pkcs7UnPadding(decrypted)
|
|
||||||
|
|
||||||
return decrypted
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package cryptor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDesEcbEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefgh"
|
|
||||||
|
|
||||||
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
|
|
||||||
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
|
|
||||||
assert.Equal(data, string(desEcbDecrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDesCbcEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefgh"
|
|
||||||
|
|
||||||
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
|
|
||||||
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
|
|
||||||
assert.Equal(data, string(desCbcDecrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDesCtrCrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefgh"
|
|
||||||
|
|
||||||
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
|
|
||||||
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestDesCtrCrypt")
|
|
||||||
assert.Equal(data, string(desCtrDeCrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDesCfbEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefgh"
|
|
||||||
|
|
||||||
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
|
|
||||||
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
|
|
||||||
assert.Equal(data, string(desCfbDecrypt))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDesOfbEncrypt(t *testing.T) {
|
|
||||||
data := "hello world"
|
|
||||||
key := "abcdefgh"
|
|
||||||
|
|
||||||
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
|
|
||||||
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
|
|
||||||
assert.Equal(data, string(desOfbDecrypt))
|
|
||||||
}
|
|
||||||
118
cryptor/rsa.go
118
cryptor/rsa.go
@@ -1,118 +0,0 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
|
||||||
// Use of this source code is governed by MIT license
|
|
||||||
|
|
||||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
|
||||||
package cryptor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GenerateRsaKey make a rsa private key, and return key file name
|
|
||||||
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
|
|
||||||
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
|
||||||
// private key
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
derText := x509.MarshalPKCS1PrivateKey(privateKey)
|
|
||||||
|
|
||||||
block := pem.Block{
|
|
||||||
Type: "rsa private key",
|
|
||||||
Bytes: derText,
|
|
||||||
}
|
|
||||||
|
|
||||||
//file,err := os.Create("rsa_private.pem")
|
|
||||||
file, err := os.Create(priKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
pem.Encode(file, &block)
|
|
||||||
file.Close()
|
|
||||||
|
|
||||||
// public key
|
|
||||||
publicKey := privateKey.PublicKey
|
|
||||||
|
|
||||||
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
block = pem.Block{
|
|
||||||
Type: "rsa public key",
|
|
||||||
Bytes: derpText,
|
|
||||||
}
|
|
||||||
|
|
||||||
//file,err = os.Create("rsa_public.pem")
|
|
||||||
file, err = os.Create(pubKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pem.Encode(file, &block)
|
|
||||||
file.Close()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RsaEncrypt encrypt data with ras algorithm
|
|
||||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
|
||||||
file, err := os.Open(pubKeyFileName)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fileInfo, err := file.Stat()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
buf := make([]byte, fileInfo.Size())
|
|
||||||
file.Read(buf)
|
|
||||||
|
|
||||||
block, _ := pem.Decode(buf)
|
|
||||||
|
|
||||||
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
pubKey := pubInterface.(*rsa.PublicKey)
|
|
||||||
|
|
||||||
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return cipherText
|
|
||||||
}
|
|
||||||
|
|
||||||
// RsaDecrypt decrypt data with ras algorithm
|
|
||||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
|
||||||
file, err := os.Open(privateKeyFileName)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fileInfo, err := file.Stat()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
buf := make([]byte, fileInfo.Size())
|
|
||||||
defer file.Close()
|
|
||||||
file.Read(buf)
|
|
||||||
|
|
||||||
block, _ := pem.Decode(buf)
|
|
||||||
|
|
||||||
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return plainText
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package cryptor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRsaEncrypt(t *testing.T) {
|
|
||||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
data := []byte("hello world")
|
|
||||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
|
||||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
|
||||||
assert.Equal(string(data), string(decrypted))
|
|
||||||
}
|
|
||||||
60
datetime/conversion.go
Normal file
60
datetime/conversion.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license.
|
||||||
|
|
||||||
|
package datetime
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type theTime struct {
|
||||||
|
unix int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnixNow return unix timestamp of current time
|
||||||
|
func NewUnixNow() *theTime {
|
||||||
|
return &theTime{unix: time.Now().Unix()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnix return unix timestamp of specified time
|
||||||
|
func NewUnix(unix int64) *theTime {
|
||||||
|
return &theTime{unix: unix}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss"
|
||||||
|
func NewFormat(t string) (*theTime, error) {
|
||||||
|
timeLayout := "2006-01-02 15:04:05"
|
||||||
|
loc := time.FixedZone("CST", 8*3600)
|
||||||
|
tt, err := time.ParseInLocation(timeLayout, t, loc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &theTime{unix: tt.Unix()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewISO8601 return unix timestamp of specified iso8601 time string
|
||||||
|
func NewISO8601(iso8601 string) (*theTime, error) {
|
||||||
|
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &theTime{unix: t.Unix()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToUnix return unix timestamp
|
||||||
|
func (t *theTime) ToUnix() int64 {
|
||||||
|
return t.unix
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time
|
||||||
|
func (t *theTime) ToFormat() string {
|
||||||
|
return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFormatForTpl return the time string which format is specified tpl
|
||||||
|
func (t *theTime) ToFormatForTpl(tpl string) string {
|
||||||
|
return time.Unix(t.unix, 0).Format(tpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFormatForTpl return iso8601 time string
|
||||||
|
func (t *theTime) ToIso8601() string {
|
||||||
|
return time.Unix(t.unix, 0).Format(time.RFC3339)
|
||||||
|
}
|
||||||
54
datetime/conversion_test.go
Normal file
54
datetime/conversion_test.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package datetime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestToUnix(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToUnix")
|
||||||
|
|
||||||
|
tm1 := NewUnixNow()
|
||||||
|
unixTimestamp := tm1.ToUnix()
|
||||||
|
tm2 := NewUnix(unixTimestamp)
|
||||||
|
|
||||||
|
assert.Equal(tm1, tm2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToFormat(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToFormat")
|
||||||
|
|
||||||
|
tm, err := NewFormat("2022/03/18 17:04:05")
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
|
||||||
|
tm, err = NewFormat("2022-03-18 17:04:05")
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
t.Log("ToFormat -> ", tm.ToFormat())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToFormatForTpl(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToFormatForTpl")
|
||||||
|
|
||||||
|
tm, err := NewFormat("2022/03/18 17:04:05")
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
|
||||||
|
tm, err = NewFormat("2022-03-18 17:04:05")
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
t.Log("ToFormatForTpl -> ", tm.ToFormatForTpl("2006/01/02 15:04:05"))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToIso8601(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToIso8601")
|
||||||
|
|
||||||
|
tm, err := NewISO8601("2022-03-18 17:04:05")
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
|
||||||
|
tm, err = NewISO8601("2006-01-02T15:04:05.999Z")
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
t.Log("ToIso8601 -> ", tm.ToIso8601())
|
||||||
|
}
|
||||||
@@ -3,29 +3,35 @@
|
|||||||
|
|
||||||
// Package datetime implements some functions to format date and time.
|
// Package datetime implements some functions to format date and time.
|
||||||
// Note:
|
// Note:
|
||||||
// 1. `format` param in FormatTimeToStr function should be as flow:
|
// 1. `format` param in FormatTimeToStr function should be as flow (case no sensitive):
|
||||||
//"yyyy-mm-dd hh:mm:ss"
|
// "yyyy-mm-dd hh:mm:ss"
|
||||||
//"yyyy-mm-dd hh:mm"
|
// "yyyy-mm-dd hh:mm"
|
||||||
//"yyyy-mm-dd hh"
|
// "yyyy-mm-dd hh"
|
||||||
//"yyyy-mm-dd"
|
// "yyyy-mm-dd"
|
||||||
//"yyyy-mm"
|
// "yyyy-mm"
|
||||||
//"mm-dd"
|
// "mm-dd"
|
||||||
//"dd-mm-yy hh:mm:ss"
|
// "dd-mm-yy hh:mm:ss"
|
||||||
//"yyyy/mm/dd hh:mm:ss"
|
// "yyyy/mm/dd hh:mm:ss"
|
||||||
//"yyyy/mm/dd hh:mm"
|
// "yyyy/mm/dd hh:mm"
|
||||||
//"yyyy/mm/dd hh"
|
// "yyyy/mm/dd hh"
|
||||||
//"yyyy/mm/dd"
|
// "yyyy/mm/dd"
|
||||||
//"yyyy/mm"
|
// "yyyy/mm"
|
||||||
//"mm/dd"
|
// "mm/dd"
|
||||||
//"dd/mm/yy hh:mm:ss"
|
// "dd/mm/yy hh:mm:ss"
|
||||||
//"yyyy"
|
// "yyyymmdd"
|
||||||
//"mm"
|
// "mmddyy"
|
||||||
//"hh:mm:ss"
|
// "yyyy"
|
||||||
//"mm:ss"
|
// "yy"
|
||||||
|
// "mm"
|
||||||
|
// "hh:mm:ss"
|
||||||
|
// "hh:mm"
|
||||||
|
// "mm:ss"
|
||||||
|
|
||||||
package datetime
|
package datetime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +41,7 @@ func init() {
|
|||||||
timeFormat = map[string]string{
|
timeFormat = map[string]string{
|
||||||
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
|
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
|
||||||
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
|
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
|
||||||
"yyyy-mm-dd hh": "2006-01-02 15:04",
|
"yyyy-mm-dd hh": "2006-01-02 15",
|
||||||
"yyyy-mm-dd": "2006-01-02",
|
"yyyy-mm-dd": "2006-01-02",
|
||||||
"yyyy-mm": "2006-01",
|
"yyyy-mm": "2006-01",
|
||||||
"mm-dd": "01-02",
|
"mm-dd": "01-02",
|
||||||
@@ -47,9 +53,13 @@ func init() {
|
|||||||
"yyyy/mm": "2006/01",
|
"yyyy/mm": "2006/01",
|
||||||
"mm/dd": "01/02",
|
"mm/dd": "01/02",
|
||||||
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
|
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
|
||||||
|
"yyyymmdd": "20060102",
|
||||||
|
"mmddyy": "010206",
|
||||||
"yyyy": "2006",
|
"yyyy": "2006",
|
||||||
|
"yy": "06",
|
||||||
"mm": "01",
|
"mm": "01",
|
||||||
"hh:mm:ss": "15:04:05",
|
"hh:mm:ss": "15:04:05",
|
||||||
|
"hh:mm": "15:04",
|
||||||
"mm:ss": "04:05",
|
"mm:ss": "04:05",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,6 +79,11 @@ func AddDay(t time.Time, day int64) time.Time {
|
|||||||
return t.Add(24 * time.Hour * time.Duration(day))
|
return t.Add(24 * time.Hour * time.Duration(day))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddYear add or sub year to the time.
|
||||||
|
func AddYear(t time.Time, year int64) time.Time {
|
||||||
|
return t.Add(365 * 24 * time.Hour * time.Duration(year))
|
||||||
|
}
|
||||||
|
|
||||||
// GetNowDate return format yyyy-mm-dd of current date
|
// GetNowDate return format yyyy-mm-dd of current date
|
||||||
func GetNowDate() string {
|
func GetNowDate() string {
|
||||||
return time.Now().Format("2006-01-02")
|
return time.Now().Format("2006-01-02")
|
||||||
@@ -97,18 +112,39 @@ func GetNightTimestamp() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FormatTimeToStr convert time to string
|
// FormatTimeToStr convert time to string
|
||||||
func FormatTimeToStr(t time.Time, format string) string {
|
func FormatTimeToStr(t time.Time, format string, timezone ...string) string {
|
||||||
return t.Format(timeFormat[format])
|
tf, ok := timeFormat[strings.ToLower(format)]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if timezone != nil && timezone[0] != "" {
|
||||||
|
loc, err := time.LoadLocation(timezone[0])
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return t.In(loc).Format(tf)
|
||||||
|
}
|
||||||
|
return t.Format(tf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatStrToTime convert string to time
|
// FormatStrToTime convert string to time
|
||||||
func FormatStrToTime(str, format string) (time.Time, error) {
|
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error) {
|
||||||
v, ok := timeFormat[format]
|
tf, ok := timeFormat[strings.ToLower(format)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return time.Time{}, fmt.Errorf("format %s not found", format)
|
return time.Time{}, fmt.Errorf("format %s not support", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
return time.Parse(v, str)
|
if timezone != nil && timezone[0] != "" {
|
||||||
|
loc, err := time.LoadLocation(timezone[0])
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.ParseInLocation(tf, str, loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Parse(tf, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeginOfMinute return beginning minute time of day
|
// BeginOfMinute return beginning minute time of day
|
||||||
@@ -180,3 +216,108 @@ func BeginOfYear(t time.Time) time.Time {
|
|||||||
func EndOfYear(t time.Time) time.Time {
|
func EndOfYear(t time.Time) time.Time {
|
||||||
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
|
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsLeapYear check if param year is leap year or not.
|
||||||
|
func IsLeapYear(year int) bool {
|
||||||
|
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BetweenSeconds returns the number of seconds between two times.
|
||||||
|
func BetweenSeconds(t1 time.Time, t2 time.Time) int64 {
|
||||||
|
index := t2.Unix() - t1.Unix()
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
// DayOfYear returns which day of the year the parameter date `t` is.
|
||||||
|
func DayOfYear(t time.Time) int {
|
||||||
|
y, m, d := t.Date()
|
||||||
|
firstDay := time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
|
||||||
|
nowDate := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
|
||||||
|
|
||||||
|
return int(nowDate.Sub(firstDay).Hours() / 24)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWeekend checks if passed time is weekend or not.
|
||||||
|
func IsWeekend(t time.Time) bool {
|
||||||
|
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NowDateOrTime return current datetime with specific format and timezone.
|
||||||
|
func NowDateOrTime(format string, timezone ...string) string {
|
||||||
|
tf, ok := timeFormat[strings.ToLower(format)]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if timezone != nil && timezone[0] != "" {
|
||||||
|
loc, err := time.LoadLocation(timezone[0])
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Now().In(loc).Format(tf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Now().Format(tf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamp return current second timestamp.
|
||||||
|
func Timestamp(timezone ...string) int64 {
|
||||||
|
t := time.Now()
|
||||||
|
|
||||||
|
if timezone != nil && timezone[0] != "" {
|
||||||
|
loc, err := time.LoadLocation(timezone[0])
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
t = t.In(loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampMilli return current mill second timestamp.
|
||||||
|
func TimestampMilli(timezone ...string) int64 {
|
||||||
|
t := time.Now()
|
||||||
|
|
||||||
|
if timezone != nil && timezone[0] != "" {
|
||||||
|
loc, err := time.LoadLocation(timezone[0])
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
t = t.In(loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampMicro return current micro second timestamp.
|
||||||
|
func TimestampMicro(timezone ...string) int64 {
|
||||||
|
t := time.Now()
|
||||||
|
|
||||||
|
if timezone != nil && timezone[0] != "" {
|
||||||
|
loc, err := time.LoadLocation(timezone[0])
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
t = t.In(loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampNano return current nano second timestamp.
|
||||||
|
func TimestampNano(timezone ...string) int64 {
|
||||||
|
t := time.Now()
|
||||||
|
|
||||||
|
if timezone != nil && timezone[0] != "" {
|
||||||
|
loc, err := time.LoadLocation(timezone[0])
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
t = t.In(loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.UnixNano()
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,6 +46,19 @@ func TestAddMinute(t *testing.T) {
|
|||||||
assert.Equal(float64(-2), diff2.Minutes())
|
assert.Equal(float64(-2), diff2.Minutes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddYear(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestAddDay")
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
after2Years := AddYear(now, 1)
|
||||||
|
diff1 := after2Years.Sub(now)
|
||||||
|
assert.Equal(float64(8760), diff1.Hours())
|
||||||
|
|
||||||
|
before2Years := AddYear(now, -1)
|
||||||
|
diff2 := before2Years.Sub(now)
|
||||||
|
assert.Equal(float64(-8760), diff2.Hours())
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetNowDate(t *testing.T) {
|
func TestGetNowDate(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestGetNowDate")
|
assert := internal.NewAssert(t, "TestGetNowDate")
|
||||||
expected := time.Now().Format("2006-01-02")
|
expected := time.Now().Format("2006-01-02")
|
||||||
@@ -231,3 +244,92 @@ func TestEndOfYear(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(expected, actual)
|
assert.Equal(expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsLeapYear(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestEndOfYear")
|
||||||
|
|
||||||
|
result1 := IsLeapYear(2000)
|
||||||
|
result2 := IsLeapYear(2001)
|
||||||
|
|
||||||
|
assert.Equal(true, result1)
|
||||||
|
assert.Equal(false, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBetweenSeconds(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestBetweenSeconds")
|
||||||
|
|
||||||
|
today := time.Now()
|
||||||
|
tomorrow := AddDay(today, 1)
|
||||||
|
yesterday := AddDay(today, -1)
|
||||||
|
|
||||||
|
result1 := BetweenSeconds(today, tomorrow)
|
||||||
|
result2 := BetweenSeconds(today, yesterday)
|
||||||
|
|
||||||
|
assert.Equal(int64(86400), result1)
|
||||||
|
assert.Equal(int64(-86400), result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDayOfYear(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDayOfYear")
|
||||||
|
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
|
||||||
|
result1 := DayOfYear(date1)
|
||||||
|
assert.Equal(31, result1)
|
||||||
|
|
||||||
|
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
|
||||||
|
result2 := DayOfYear(date2)
|
||||||
|
assert.Equal(1, result2)
|
||||||
|
|
||||||
|
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
|
||||||
|
result3 := DayOfYear(date3)
|
||||||
|
assert.Equal(0, result3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsWeekend(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsWeekend")
|
||||||
|
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||||
|
result := IsWeekend(date)
|
||||||
|
assert.Equal(true, result)
|
||||||
|
|
||||||
|
date1 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||||
|
result1 := IsWeekend(date1)
|
||||||
|
assert.Equal(true, result1)
|
||||||
|
|
||||||
|
date2 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||||
|
result2 := IsWeekend(date2)
|
||||||
|
assert.Equal(false, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNowDateOrTime(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
formats := []string{
|
||||||
|
"yyyy-mm-dd hh:mm:ss",
|
||||||
|
"yyyy-mm-dd",
|
||||||
|
"dd-mm-yy hh:mm:ss",
|
||||||
|
"yyyy/mm/dd hh:mm:ss",
|
||||||
|
"hh:mm:ss",
|
||||||
|
"yyyy/mm",
|
||||||
|
"yyyy-mm-dd hh",
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(formats); i++ {
|
||||||
|
result := NowDateOrTime(formats[i], "UTC")
|
||||||
|
t.Log(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimestamp(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ts1 := Timestamp()
|
||||||
|
t.Log(ts1)
|
||||||
|
|
||||||
|
ts2 := TimestampMilli()
|
||||||
|
t.Log(ts2)
|
||||||
|
|
||||||
|
ts3 := TimestampMicro()
|
||||||
|
t.Log(ts3)
|
||||||
|
|
||||||
|
ts4 := TimestampNano()
|
||||||
|
t.Log(ts4)
|
||||||
|
}
|
||||||
|
|||||||
326
docs/compare.md
Normal file
326
docs/compare.md
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
# Compare
|
||||||
|
|
||||||
|
Package compare provides a lightweight comparison function on any type.
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Source:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/condition"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Equal](#Equal)
|
||||||
|
- [EqualValue](#EqualValue)
|
||||||
|
- [LessThan](#LessThan)
|
||||||
|
- [GreaterThan](#GreaterThan)
|
||||||
|
- [LessOrEqual](#LessOrEqual)
|
||||||
|
- [GreaterOrEqual](#GreaterOrEqual)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### <span id="Equal">Equal</span>
|
||||||
|
|
||||||
|
<p>Checks if two values are equal or not. (check both type and value)</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Equal(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.Equal(1, 1)
|
||||||
|
result2 := compare.Equal("1", "1")
|
||||||
|
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||||
|
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||||
|
|
||||||
|
result5 := compare.Equal(1, "1")
|
||||||
|
result6 := compare.Equal(1, int64(1))
|
||||||
|
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="EqualValue">EqualValue</span>
|
||||||
|
|
||||||
|
<p>Checks if two values are equal or not. (check value only)</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EqualValue(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.EqualValue(1, 1)
|
||||||
|
result2 := compare.EqualValue(int(1), int64(1))
|
||||||
|
result3 := compare.EqualValue(1, "1")
|
||||||
|
result4 := compare.EqualValue(1, "2")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="LessThan">LessThan</span>
|
||||||
|
|
||||||
|
<p>Checks if value `left` less than value `right`.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func LessThan(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.LessThan(1, 2)
|
||||||
|
result2 := compare.LessThan(1.1, 2.2)
|
||||||
|
result3 := compare.LessThan("a", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.LessThan(time1, time2)
|
||||||
|
|
||||||
|
result5 := compare.LessThan(2, 1)
|
||||||
|
result6 := compare.LessThan(1, int64(2))
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GreaterThan">GreaterThan</span>
|
||||||
|
|
||||||
|
<p>Checks if value `left` greater than value `right`.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GreaterThan(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.GreaterThan(2, 1)
|
||||||
|
result2 := compare.GreaterThan(2.2, 1.1)
|
||||||
|
result3 := compare.GreaterThan("b", "a")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.GreaterThan(time2, time1)
|
||||||
|
|
||||||
|
result5 := compare.GreaterThan(1, 2)
|
||||||
|
result6 := compare.GreaterThan(int64(2), 1)
|
||||||
|
result7 := compare.GreaterThan("b", "c")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="LessOrEqual">LessOrEqual</span>
|
||||||
|
|
||||||
|
<p>Checks if value `left` less than or equal than value `right`.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func LessOrEqual(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.LessOrEqual(1, 1)
|
||||||
|
result2 := compare.LessOrEqual(1.1, 2.2)
|
||||||
|
result3 := compare.LessOrEqual("a", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.LessOrEqual(time1, time2)
|
||||||
|
|
||||||
|
result5 := compare.LessOrEqual(2, 1)
|
||||||
|
result6 := compare.LessOrEqual(1, int64(2))
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GreaterOrEqual">GreaterOrEqual</span>
|
||||||
|
|
||||||
|
<p>Checks if value `left` less greater or equal than value `right`.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GreaterOrEqual(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.GreaterOrEqual(1, 1)
|
||||||
|
result2 := compare.GreaterOrEqual(2.2, 1.1)
|
||||||
|
result3 := compare.GreaterOrEqual("b", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.GreaterOrEqual(time2, time1)
|
||||||
|
|
||||||
|
result5 := compare.GreaterOrEqual(1, 2)
|
||||||
|
result6 := compare.GreaterOrEqual(int64(2), 1)
|
||||||
|
result7 := compare.GreaterOrEqual("b", "c")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
326
docs/compare_zh-CN.md
Normal file
326
docs/compare_zh-CN.md
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
# Compare
|
||||||
|
|
||||||
|
compare包提供几个轻量级的类型比较函数。
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 源码:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 用法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/condition"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [Equal](#Equal)
|
||||||
|
- [EqualValue](#EqualValue)
|
||||||
|
- [LessThan](#LessThan)
|
||||||
|
- [GreaterThan](#GreaterThan)
|
||||||
|
- [LessOrEqual](#LessOrEqual)
|
||||||
|
- [GreaterOrEqual](#GreaterOrEqual)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### <span id="Equal">Equal</span>
|
||||||
|
|
||||||
|
<p>检查两个值是否相等(检查类型和值)</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Equal(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.Equal(1, 1)
|
||||||
|
result2 := compare.Equal("1", "1")
|
||||||
|
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||||
|
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||||
|
|
||||||
|
result5 := compare.Equal(1, "1")
|
||||||
|
result6 := compare.Equal(1, int64(1))
|
||||||
|
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="EqualValue">EqualValue</span>
|
||||||
|
|
||||||
|
<p>检查两个值是否相等(只检查值)</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EqualValue(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.EqualValue(1, 1)
|
||||||
|
result2 := compare.EqualValue(int(1), int64(1))
|
||||||
|
result3 := compare.EqualValue(1, "1")
|
||||||
|
result4 := compare.EqualValue(1, "2")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="LessThan">LessThan</span>
|
||||||
|
|
||||||
|
<p>验证参数`left`的值是否小于参数`right`的值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func LessThan(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.LessThan(1, 2)
|
||||||
|
result2 := compare.LessThan(1.1, 2.2)
|
||||||
|
result3 := compare.LessThan("a", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.LessThan(time1, time2)
|
||||||
|
|
||||||
|
result5 := compare.LessThan(2, 1)
|
||||||
|
result6 := compare.LessThan(1, int64(2))
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GreaterThan">GreaterThan</span>
|
||||||
|
|
||||||
|
<p>验证参数`left`的值是否大于参数`right`的值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GreaterThan(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.GreaterThan(2, 1)
|
||||||
|
result2 := compare.GreaterThan(2.2, 1.1)
|
||||||
|
result3 := compare.GreaterThan("b", "a")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.GreaterThan(time2, time1)
|
||||||
|
|
||||||
|
result5 := compare.GreaterThan(1, 2)
|
||||||
|
result6 := compare.GreaterThan(int64(2), 1)
|
||||||
|
result7 := compare.GreaterThan("b", "c")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="LessOrEqual">LessOrEqual</span>
|
||||||
|
|
||||||
|
<p>验证参数`left`的值是否小于或等于参数`right`的值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func LessOrEqual(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.LessOrEqual(1, 1)
|
||||||
|
result2 := compare.LessOrEqual(1.1, 2.2)
|
||||||
|
result3 := compare.LessOrEqual("a", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.LessOrEqual(time1, time2)
|
||||||
|
|
||||||
|
result5 := compare.LessOrEqual(2, 1)
|
||||||
|
result6 := compare.LessOrEqual(1, int64(2))
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GreaterOrEqual">GreaterOrEqual</span>
|
||||||
|
|
||||||
|
<p>验证参数`left`的值是否大于或参数`right`的值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GreaterOrEqual(left, right any) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := compare.GreaterOrEqual(1, 1)
|
||||||
|
result2 := compare.GreaterOrEqual(2.2, 1.1)
|
||||||
|
result3 := compare.GreaterOrEqual("b", "b")
|
||||||
|
|
||||||
|
time1 := time.Now()
|
||||||
|
time2 := time1.Add(time.Second)
|
||||||
|
result4 := compare.GreaterOrEqual(time2, time1)
|
||||||
|
|
||||||
|
result5 := compare.GreaterOrEqual(1, 2)
|
||||||
|
result6 := compare.GreaterOrEqual(int64(2), 1)
|
||||||
|
result7 := compare.GreaterOrEqual("b", "c")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
# Convertor
|
# Convertor
|
||||||
|
|
||||||
Package convertor contains some functions for data type convertion.
|
Package convertor contains some functions for data type convertion.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
|
[https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go](https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/convertor"
|
"github.com/duke-git/lancet/convertor"
|
||||||
@@ -19,23 +21,33 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [ColorHexToRGB](#ColorHexToRGB)
|
|
||||||
- [ColorRGBToHex](#ColorRGBToHex)
|
- [ColorHexToRGB](#ColorHexToRGB)
|
||||||
- [ToBool](#ToBool)
|
- [ColorRGBToHex](#ColorRGBToHex)
|
||||||
- [ToBytes](#ToBytes)
|
- [ToBool](#ToBool)
|
||||||
- [ToChar](#ToChar)
|
- [ToBytes](#ToBytes)
|
||||||
- [ToInt](#ToInt)
|
- [ToChar](#ToChar)
|
||||||
- [ToJson](#ToJson)
|
- [ToChannel](#ToChannel)
|
||||||
- [ToString](#ToString)
|
- [ToFloat](#ToFloat)
|
||||||
- [StructToMap](#StructToMap)
|
- [ToInt](#ToInt)
|
||||||
|
- [ToJson](#ToJson)
|
||||||
|
- [ToString](#ToString)
|
||||||
|
- [StructToMap](#StructToMap)
|
||||||
|
- [EncodeByte](#EncodeByte)
|
||||||
|
- [DecodeByte](#DecodeByte)
|
||||||
|
- [DeepClone](#DeepClone)
|
||||||
|
- [CopyProperties](#CopyProperties)
|
||||||
|
- [ToInterface](#ToInterface)
|
||||||
|
- [Utf8ToGbk](#Utf8ToGbk)
|
||||||
|
- [GbkToUtf8](#GbkToUtf8)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||||
|
|
||||||
<p>Convert color hex to color rgb.</p>
|
<p>Convert color hex to color rgb.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -43,6 +55,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -60,8 +73,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
||||||
|
|
||||||
<p>Convert color rgb to color hex.</p>
|
<p>Convert color rgb to color hex.</p>
|
||||||
@@ -71,6 +82,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ColorRGBToHex(red, green, blue int) string
|
func ColorRGBToHex(red, green, blue int) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -91,8 +103,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToBool">ToBool</span>
|
### <span id="ToBool">ToBool</span>
|
||||||
|
|
||||||
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
|
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
|
||||||
@@ -102,6 +112,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToBool(s string) (bool, error)
|
func ToBool(s string) (bool, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -127,8 +138,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToBytes">ToBytes</span>
|
### <span id="ToBytes">ToBytes</span>
|
||||||
|
|
||||||
<p>Convert interface to byte slice.</p>
|
<p>Convert interface to byte slice.</p>
|
||||||
@@ -138,6 +147,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToBytes(data interface{}) ([]byte, error)
|
func ToBytes(data interface{}) ([]byte, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -157,8 +167,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToChar">ToChar</span>
|
### <span id="ToChar">ToChar</span>
|
||||||
|
|
||||||
<p>Convert string to char slice.</p>
|
<p>Convert string to char slice.</p>
|
||||||
@@ -168,6 +176,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToChar(s string) []string
|
func ToChar(s string) []string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -190,7 +199,42 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ToChannel">ToChannel</span>
|
||||||
|
|
||||||
|
<p>Convert a collection of elements to a read-only channels.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToChannel(array []interface{}) <-chan interface{}
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ch := convertor.ToChannel([]int{1, 2, 3})
|
||||||
|
|
||||||
|
val1, _ := <-ch
|
||||||
|
fmt.Println(val1) //1
|
||||||
|
|
||||||
|
val2, _ := <-ch
|
||||||
|
fmt.Println(val2) //2
|
||||||
|
|
||||||
|
val3, _ := <-ch
|
||||||
|
fmt.Println(val3) //3
|
||||||
|
|
||||||
|
_, ok := <-ch
|
||||||
|
fmt.Println(ok) //false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="ToFloat">ToFloat</span>
|
### <span id="ToFloat">ToFloat</span>
|
||||||
|
|
||||||
@@ -201,6 +245,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToFloat(value interface{}) (float64, error)
|
func ToFloat(value interface{}) (float64, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -223,8 +268,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToInt">ToInt</span>
|
### <span id="ToInt">ToInt</span>
|
||||||
|
|
||||||
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||||
@@ -234,6 +277,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToInt(value interface{}) (int64, error)
|
func ToInt(value interface{}) (int64, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -256,8 +300,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToJson">ToJson</span>
|
### <span id="ToJson">ToJson</span>
|
||||||
|
|
||||||
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
|
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
|
||||||
@@ -267,6 +309,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToJson(value interface{}) (string, error)
|
func ToJson(value interface{}) (string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -284,8 +327,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToString">ToString</span>
|
### <span id="ToString">ToString</span>
|
||||||
|
|
||||||
<p>Convert interface to string. </p>
|
<p>Convert interface to string. </p>
|
||||||
@@ -295,6 +336,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToString(value interface{}) string
|
func ToString(value interface{}) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -312,8 +354,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="StructToMap">StructToMap</span>
|
### <span id="StructToMap">StructToMap</span>
|
||||||
|
|
||||||
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
|
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
|
||||||
@@ -323,6 +363,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func StructToMap(value interface{}) (map[string]interface{}, error)
|
func StructToMap(value interface{}) (map[string]interface{}, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -346,4 +387,303 @@ func main() {
|
|||||||
|
|
||||||
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="EncodeByte">EncodeByte</span>
|
||||||
|
|
||||||
|
<p>Encode data to byte slice.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EncodeByte(data any) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
byteData, _ := convertor.EncodeByte("abc")
|
||||||
|
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="DecodeByte">DecodeByte</span>
|
||||||
|
|
||||||
|
<p>Decode byte data to target object. target should be a pointer instance.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func DecodeByte(data []byte, target any) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var result string
|
||||||
|
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
|
convertor.DecodeByte(byteData, &result)
|
||||||
|
fmt.Println(result) //"abc"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="DeepClone">DeepClone</span>
|
||||||
|
|
||||||
|
<p>Creates a deep copy of passed item, can't clone unexported field of struct.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func DeepClone[T any](src T) T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Struct struct {
|
||||||
|
Str string
|
||||||
|
Int int
|
||||||
|
Float float64
|
||||||
|
Bool bool
|
||||||
|
Nil interface{}
|
||||||
|
unexported string
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []interface{}{
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
0.1,
|
||||||
|
map[string]int{
|
||||||
|
"a": 1,
|
||||||
|
"b": 2,
|
||||||
|
},
|
||||||
|
&Struct{
|
||||||
|
Str: "test",
|
||||||
|
Int: 1,
|
||||||
|
Float: 0.1,
|
||||||
|
Bool: true,
|
||||||
|
Nil: nil,
|
||||||
|
// unexported: "can't be cloned",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range cases {
|
||||||
|
cloned := convertor.DeepClone(item)
|
||||||
|
|
||||||
|
isPointerEqual := &cloned == &item
|
||||||
|
fmt.Println(cloned, isPointerEqual)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true false
|
||||||
|
// 1 false
|
||||||
|
// 0.1 false
|
||||||
|
// map[a:1 b:2] false
|
||||||
|
// &{test 1 0.1 true <nil> } false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="CopyProperties">CopyProperties</span>
|
||||||
|
|
||||||
|
<p>Copies each field from the source struct into the destination struct. Use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CopyProperties(dst, src interface{}) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Disk struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiskVO struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Indicator struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int `json:"cpu"`
|
||||||
|
Disk []Disk `json:"disk"`
|
||||||
|
Stop chan bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IndicatorVO struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int64 `json:"cpu"`
|
||||||
|
Disk []DiskVO `json:"disk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||||
|
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||||
|
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||||
|
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||||
|
}}
|
||||||
|
|
||||||
|
indicatorVO := IndicatorVO{}
|
||||||
|
|
||||||
|
err := convertor.CopyProperties(&indicatorVO, indicator)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(indicatorVO.Id)
|
||||||
|
fmt.Println(indicatorVO.Ip)
|
||||||
|
fmt.Println(len(indicatorVO.Disk))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 001
|
||||||
|
// 127.0.0.1
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToInterface">ToInterface</span>
|
||||||
|
|
||||||
|
<p>Converts reflect value to its interface type.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToInterface(v reflect.Value) (value interface{}, ok bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
val := reflect.ValueOf("abc")
|
||||||
|
iVal, ok := convertor.ToInterface(val)
|
||||||
|
|
||||||
|
fmt.Printf("%T\n", iVal)
|
||||||
|
fmt.Printf("%v\n", iVal)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// string
|
||||||
|
// abc
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Utf8ToGbk">Utf8ToGbk</span>
|
||||||
|
|
||||||
|
<p>Converts utf8 encoding data to GBK encoding data.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Utf8ToGbk(bs []byte) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
utf8Data := []byte("hello")
|
||||||
|
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
|
||||||
|
|
||||||
|
fmt.Println(utf8.Valid(utf8Data))
|
||||||
|
fmt.Println(validator.IsGBK(gbkData))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GbkToUtf8">GbkToUtf8</span>
|
||||||
|
|
||||||
|
<p>Converts GBK encoding data to utf8 encoding data.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GbkToUtf8(bs []byte) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
|
||||||
|
utf8Data, _ := convertor.GbkToUtf8(gbkData)
|
||||||
|
|
||||||
|
fmt.Println(utf8.Valid(utf8Data))
|
||||||
|
fmt.Println(string(utf8Data))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// hello
|
||||||
|
}
|
||||||
```
|
```
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
# Convertor
|
# Convertor
|
||||||
convertor转换器包支持一些常见的数据类型转换
|
|
||||||
|
convertor 转换器包支持一些常见的数据类型转换
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
|
[https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go](https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -21,23 +22,31 @@ import (
|
|||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
|
|
||||||
- [ColorHexToRGB](#ColorHexToRGB)
|
- [ColorHexToRGB](#ColorHexToRGB)
|
||||||
- [ColorRGBToHex](#ColorRGBToHex)
|
- [ColorRGBToHex](#ColorRGBToHex)
|
||||||
- [ToBool](#ToBool)
|
- [ToBool](#ToBool)
|
||||||
- [ToBytes](#ToBytes)
|
- [ToBytes](#ToBytes)
|
||||||
- [ToChar](#ToChar)
|
- [ToChar](#ToChar)
|
||||||
- [ToInt](#ToInt)
|
- [ToChannel](#ToChannel)
|
||||||
- [ToJson](#ToJson)
|
- [ToFloat](#ToFloat)
|
||||||
- [ToString](#ToString)
|
- [ToInt](#ToInt)
|
||||||
- [StructToMap](#StructToMap)
|
- [ToJson](#ToJson)
|
||||||
|
- [ToString](#ToString)
|
||||||
|
- [StructToMap](#StructToMap)
|
||||||
|
- [EncodeByte](#EncodeByte)
|
||||||
|
- [DecodeByte](#DecodeByte)
|
||||||
|
- [DeepClone](#DeepClone)
|
||||||
|
- [CopyProperties](#CopyProperties)
|
||||||
|
- [ToInterface](#ToInterface)
|
||||||
|
- [Utf8ToGbk](#Utf8ToGbk)
|
||||||
|
- [GbkToUtf8](#GbkToUtf8)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||||
|
|
||||||
<p>颜色值十六进制转rgb</p>
|
<p>颜色值十六进制转rgb</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -45,6 +54,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -62,8 +72,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
||||||
|
|
||||||
<p>颜色值rgb转十六进制</p>
|
<p>颜色值rgb转十六进制</p>
|
||||||
@@ -73,6 +81,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ColorRGBToHex(red, green, blue int) string
|
func ColorRGBToHex(red, green, blue int) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -93,8 +102,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToBool">ToBool</span>
|
### <span id="ToBool">ToBool</span>
|
||||||
|
|
||||||
<p>字符串转布尔类型,使用strconv.ParseBool</p>
|
<p>字符串转布尔类型,使用strconv.ParseBool</p>
|
||||||
@@ -104,6 +111,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToBool(s string) (bool, error)
|
func ToBool(s string) (bool, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -129,8 +137,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToBytes">ToBytes</span>
|
### <span id="ToBytes">ToBytes</span>
|
||||||
|
|
||||||
<p>interface转字节切片.</p>
|
<p>interface转字节切片.</p>
|
||||||
@@ -140,6 +146,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToBytes(data interface{}) ([]byte, error)
|
func ToBytes(data interface{}) ([]byte, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -159,8 +166,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToChar">ToChar</span>
|
### <span id="ToChar">ToChar</span>
|
||||||
|
|
||||||
<p>字符串转字符切片</p>
|
<p>字符串转字符切片</p>
|
||||||
@@ -170,6 +175,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToChar(s string) []string
|
func ToChar(s string) []string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -192,7 +198,42 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ToChannel">ToChannel</span>
|
||||||
|
|
||||||
|
<p>将切片转为只读channel</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToChannel(array []interface{}) <-chan interface{}
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ch := convertor.ToChannel([]int{1, 2, 3})
|
||||||
|
|
||||||
|
val1, _ := <-ch
|
||||||
|
fmt.Println(val1) //1
|
||||||
|
|
||||||
|
val2, _ := <-ch
|
||||||
|
fmt.Println(val2) //2
|
||||||
|
|
||||||
|
val3, _ := <-ch
|
||||||
|
fmt.Println(val3) //3
|
||||||
|
|
||||||
|
_, ok := <-ch
|
||||||
|
fmt.Println(ok) //false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="ToFloat">ToFloat</span>
|
### <span id="ToFloat">ToFloat</span>
|
||||||
|
|
||||||
@@ -203,6 +244,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToFloat(value interface{}) (float64, error)
|
func ToFloat(value interface{}) (float64, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -225,8 +267,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToInt">ToInt</span>
|
### <span id="ToInt">ToInt</span>
|
||||||
|
|
||||||
<p>将interface转成intt64类型,如果参数无法转换,会返回0和error</p>
|
<p>将interface转成intt64类型,如果参数无法转换,会返回0和error</p>
|
||||||
@@ -236,6 +276,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToInt(value interface{}) (int64, error)
|
func ToInt(value interface{}) (int64, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -258,8 +299,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToJson">ToJson</span>
|
### <span id="ToJson">ToJson</span>
|
||||||
|
|
||||||
<p>将interface转成json字符串,如果参数无法转换,会返回""和error</p>
|
<p>将interface转成json字符串,如果参数无法转换,会返回""和error</p>
|
||||||
@@ -269,6 +308,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToJson(value interface{}) (string, error)
|
func ToJson(value interface{}) (string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -286,8 +326,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ToString">ToString</span>
|
### <span id="ToString">ToString</span>
|
||||||
|
|
||||||
<p>将interface转成字符串</p>
|
<p>将interface转成字符串</p>
|
||||||
@@ -297,6 +335,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ToString(value interface{}) string
|
func ToString(value interface{}) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -314,8 +353,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="StructToMap">StructToMap</span>
|
### <span id="StructToMap">StructToMap</span>
|
||||||
|
|
||||||
<p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
|
<p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
|
||||||
@@ -325,6 +362,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func StructToMap(value interface{}) (map[string]interface{}, error)
|
func StructToMap(value interface{}) (map[string]interface{}, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>列子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -348,4 +386,304 @@ func main() {
|
|||||||
|
|
||||||
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="EncodeByte">EncodeByte</span>
|
||||||
|
|
||||||
|
<p>将data编码成字节切片</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EncodeByte(data any) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
byteData, _ := convertor.EncodeByte("abc")
|
||||||
|
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="DecodeByte">DecodeByte</span>
|
||||||
|
|
||||||
|
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func DecodeByte(data []byte, target any) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var result string
|
||||||
|
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
|
convertor.DecodeByte(byteData, &result)
|
||||||
|
fmt.Println(result) //"abc"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="DeepClone">DeepClone</span>
|
||||||
|
|
||||||
|
<p>创建一个传入值的深拷贝, 无法克隆结构体的非导出字段。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func DeepClone[T any](src T) T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Struct struct {
|
||||||
|
Str string
|
||||||
|
Int int
|
||||||
|
Float float64
|
||||||
|
Bool bool
|
||||||
|
Nil interface{}
|
||||||
|
unexported string
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []interface{}{
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
0.1,
|
||||||
|
map[string]int{
|
||||||
|
"a": 1,
|
||||||
|
"b": 2,
|
||||||
|
},
|
||||||
|
&Struct{
|
||||||
|
Str: "test",
|
||||||
|
Int: 1,
|
||||||
|
Float: 0.1,
|
||||||
|
Bool: true,
|
||||||
|
Nil: nil,
|
||||||
|
// unexported: "can't be cloned",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range cases {
|
||||||
|
cloned := convertor.DeepClone(item)
|
||||||
|
|
||||||
|
isPointerEqual := &cloned == &item
|
||||||
|
fmt.Println(cloned, isPointerEqual)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true false
|
||||||
|
// 1 false
|
||||||
|
// 0.1 false
|
||||||
|
// map[a:1 b:2] false
|
||||||
|
// &{test 1 0.1 true <nil> } false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="CopyProperties">CopyProperties</span>
|
||||||
|
|
||||||
|
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化,需要设置dst和src struct字段的json tag。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CopyProperties(dst, src interface{}) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Disk struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiskVO struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Indicator struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int `json:"cpu"`
|
||||||
|
Disk []Disk `json:"disk"`
|
||||||
|
Stop chan bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IndicatorVO struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int64 `json:"cpu"`
|
||||||
|
Disk []DiskVO `json:"disk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||||
|
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||||
|
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||||
|
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||||
|
}}
|
||||||
|
|
||||||
|
indicatorVO := IndicatorVO{}
|
||||||
|
|
||||||
|
err := convertor.CopyProperties(&indicatorVO, indicator)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(indicatorVO.Id)
|
||||||
|
fmt.Println(indicatorVO.Ip)
|
||||||
|
fmt.Println(len(indicatorVO.Disk))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 001
|
||||||
|
// 127.0.0.1
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToInterface">ToInterface</span>
|
||||||
|
|
||||||
|
<p>将反射值转换成对应的interface类型。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToInterface(v reflect.Value) (value interface{}, ok bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
val := reflect.ValueOf("abc")
|
||||||
|
iVal, ok := convertor.ToInterface(val)
|
||||||
|
|
||||||
|
fmt.Printf("%T\n", iVal)
|
||||||
|
fmt.Printf("%v\n", iVal)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// string
|
||||||
|
// abc
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Utf8ToGbk">Utf8ToGbk</span>
|
||||||
|
|
||||||
|
<p>utf8编码转GBK编码。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Utf8ToGbk(bs []byte) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
utf8Data := []byte("hello")
|
||||||
|
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
|
||||||
|
|
||||||
|
fmt.Println(utf8.Valid(utf8Data))
|
||||||
|
fmt.Println(validator.IsGBK(gbkData))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GbkToUtf8">GbkToUtf8</span>
|
||||||
|
|
||||||
|
<p>GBK编码转utf8编码。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GbkToUtf8(bs []byte) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
|
||||||
|
utf8Data, _ := convertor.GbkToUtf8(gbkData)
|
||||||
|
|
||||||
|
fmt.Println(utf8.Valid(utf8Data))
|
||||||
|
fmt.Println(string(utf8Data))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// hello
|
||||||
|
}
|
||||||
```
|
```
|
||||||
648
docs/cryptor.md
648
docs/cryptor.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
817
docs/datetime.md
817
docs/datetime.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
546
docs/fileutil.md
546
docs/fileutil.md
@@ -1,15 +1,17 @@
|
|||||||
# Fileutil
|
# Fileutil
|
||||||
|
|
||||||
Package fileutil implements some basic functions for file operations.
|
Package fileutil implements some basic functions for file operations.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
|
[https://github.com/duke-git/lancet/blob/v1/fileutil/file.go](https://github.com/duke-git/lancet/blob/v1/fileutil/file.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/fileutil"
|
"github.com/duke-git/lancet/fileutil"
|
||||||
@@ -19,29 +21,40 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [ClearFile](#ClearFile)
|
|
||||||
- [CreateFile](#CreateFile)
|
|
||||||
- [CopyFile](#CopyFile)
|
|
||||||
- [FileMode](#FileMode)
|
|
||||||
- [MiMeType](#MiMeType)
|
|
||||||
- [IsExist](#IsExist)
|
|
||||||
- [IsLink](#IsLink)
|
|
||||||
- [IsDir](#IsDir)
|
|
||||||
- [ListFileNames](#ListFileNames)
|
|
||||||
- [RemoveFile](#RemoveFile)
|
|
||||||
- [ReadFileToString](#ReadFileToString)
|
|
||||||
- [ReadFileByLine](#ReadFileByLine)
|
|
||||||
- [Zip](#Zip)
|
|
||||||
|
|
||||||
- [UnZip](#UnZip)
|
- [ClearFile](#ClearFile)
|
||||||
|
- [CreateFile](#CreateFile)
|
||||||
|
- [CreateDir](#CreateDir)
|
||||||
|
- [CopyFile](#CopyFile)
|
||||||
|
- [FileMode](#FileMode)
|
||||||
|
- [MiMeType](#MiMeType)
|
||||||
|
- [IsExist](#IsExist)
|
||||||
|
- [IsLink](#IsLink)
|
||||||
|
- [IsDir](#IsDir)
|
||||||
|
- [ListFileNames](#ListFileNames)
|
||||||
|
- [RemoveFile](#RemoveFile)
|
||||||
|
- [ReadFileToString](#ReadFileToString)
|
||||||
|
- [ReadFileByLine](#ReadFileByLine)
|
||||||
|
- [Zip](#Zip)
|
||||||
|
- [UnZip](#UnZip)
|
||||||
|
- [ZipAppendEntry](#ZipAppendEntry)
|
||||||
|
- [CurrentPath](#CurrentPath)
|
||||||
|
- [IsZipFile](#IsZipFile)
|
||||||
|
- [FileSize](#FileSize)
|
||||||
|
- [MTime](#MTime)
|
||||||
|
- [Sha](#Sha)
|
||||||
|
- [ReadCsvFile](#ReadCsvFile)
|
||||||
|
- [WriteCsvFile](#WriteCsvFile)
|
||||||
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
|
- [ReadFile](#ReadFile)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ClearFile">ClearFile</span>
|
### <span id="ClearFile">ClearFile</span>
|
||||||
|
|
||||||
<p>Clear the file content, write empty string to the file.</p>
|
<p>Clear the file content, write empty string to the file.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -49,6 +62,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func ClearFile(path string) error
|
func ClearFile(path string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -67,7 +81,34 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="CreateDir">CreateDir</span>
|
||||||
|
|
||||||
|
<p>Create directory in absolute path. param `absPath` like /a/, /a/b/.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CreateDir(absPath string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := fileutil.CreateDir("/a/")
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="CreateFile">CreateFile</span>
|
### <span id="CreateFile">CreateFile</span>
|
||||||
|
|
||||||
<p>Create file in path. return true if create succeed.</p>
|
<p>Create file in path. return true if create succeed.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -75,6 +116,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func CreateFile(path string) bool
|
func CreateFile(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -91,8 +133,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="CopyFile">CopyFile</span>
|
### <span id="CopyFile">CopyFile</span>
|
||||||
|
|
||||||
<p>Copy src file to dest file. If dest file exist will overwrite it.</p>
|
<p>Copy src file to dest file. If dest file exist will overwrite it.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -100,6 +142,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func CopyFile(srcFilePath string, dstFilePath string) error
|
func CopyFile(srcFilePath string, dstFilePath string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -112,15 +155,14 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
|
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="FileMode">FileMode</span>
|
### <span id="FileMode">FileMode</span>
|
||||||
|
|
||||||
<p>Return file mode infomation.</p>
|
<p>Return file mode infomation.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -128,6 +170,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func FileMode(path string) (fs.FileMode, error)
|
func FileMode(path string) (fs.FileMode, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -140,16 +183,15 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
mode, err := fileutil.FileMode("./test.txt")
|
mode, err := fileutil.FileMode("./test.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
fmt.Println(mode)
|
fmt.Println(mode)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="MiMeType">MiMeType</span>
|
### <span id="MiMeType">MiMeType</span>
|
||||||
|
|
||||||
<p>Get file mime type, 'file' param's type should be string or *os.File.</p>
|
<p>Get file mime type, 'file' param's type should be string or *os.File.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -157,6 +199,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func MiMeType(file interface{}) string
|
func MiMeType(file interface{}) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -178,10 +221,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsExist">IsExist</span>
|
### <span id="IsExist">IsExist</span>
|
||||||
|
|
||||||
<p>Checks if a file or directory exists.</p>
|
<p>Checks if a file or directory exists.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -189,6 +230,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsExist(path string) bool
|
func IsExist(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -206,9 +248,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsLink">IsLink</span>
|
### <span id="IsLink">IsLink</span>
|
||||||
|
|
||||||
<p>Checks if a file is symbol link or not.</p>
|
<p>Checks if a file is symbol link or not.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -216,6 +257,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsLink(path string) bool
|
func IsLink(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -232,16 +274,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsDir">IsDir</span>
|
### <span id="IsDir">IsDir</span>
|
||||||
|
|
||||||
<p>Checks if the path is directy or not.</p>
|
<p>Checks if the path is directy or not.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func IsDir(path string) bool
|
func IsDir(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -261,9 +303,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ListFileNames">ListFileNames</span>
|
### <span id="ListFileNames">ListFileNames</span>
|
||||||
|
|
||||||
<p>List all file names in given path.</p>
|
<p>List all file names in given path.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -271,6 +312,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ListFileNames(path string) ([]string, error)
|
func ListFileNames(path string) ([]string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -287,9 +329,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RemoveFile">RemoveFile</span>
|
### <span id="RemoveFile">RemoveFile</span>
|
||||||
|
|
||||||
<p>Remove the file of path.</p>
|
<p>Remove the file of path.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -297,6 +338,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RemoveFile(path string) error
|
func RemoveFile(path string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -310,13 +352,13 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
err := fileutil.RemoveFile("./test.txt")
|
err := fileutil.RemoveFile("./test.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="ReadFileToString">ReadFileToString</span>
|
### <span id="ReadFileToString">ReadFileToString</span>
|
||||||
|
|
||||||
<p>Return string of file content.</p>
|
<p>Return string of file content.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -324,6 +366,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ReadFileToString(path string) (string, error)
|
func ReadFileToString(path string) (string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -337,19 +380,18 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
path := "./test.txt"
|
path := "./test.txt"
|
||||||
fileutil.CreateFile(path)
|
fileutil.CreateFile(path)
|
||||||
|
|
||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
f.WriteString("hello world")
|
f.WriteString("hello world")
|
||||||
|
|
||||||
content, _ := fileutil.ReadFileToString(path)
|
content, _ := fileutil.ReadFileToString(path)
|
||||||
fmt.Println(content) //hello world
|
fmt.Println(content) //hello world
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ReadFileByLine">ReadFileByLine</span>
|
### <span id="ReadFileByLine">ReadFileByLine</span>
|
||||||
|
|
||||||
<p>Read file line by line, and return slice of lines</p>
|
<p>Read file line by line, and return slice of lines</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -357,6 +399,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ReadFileByLine(path string)([]string, error)
|
func ReadFileByLine(path string)([]string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -370,20 +413,19 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
path := "./text.txt"
|
path := "./text.txt"
|
||||||
fileutil.CreateFile(path)
|
fileutil.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")
|
f.WriteString("hello\nworld")
|
||||||
|
|
||||||
contents, _ := fileutil.ReadFileByLine(path)
|
contents, _ := fileutil.ReadFileByLine(path)
|
||||||
fmt.Println(contents) //[]string{"hello", "world"}
|
fmt.Println(contents) //[]string{"hello", "world"}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Zip">Zip</span>
|
### <span id="Zip">Zip</span>
|
||||||
|
|
||||||
<p>Create a zip file of fpath, fpath could be a file or a directory.</p>
|
<p>Create a zip file of fpath, fpath could be a file or a directory.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -391,6 +433,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Zip(fpath string, destPath string) error
|
func Zip(fpath string, destPath string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -402,17 +445,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := fileutil.Zip("./test.txt", "./test.zip")
|
err := fileutil.Zip("./test.txt", "./test.zip")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="UnZip">UnZip</span>
|
### <span id="UnZip">UnZip</span>
|
||||||
|
|
||||||
<p>Unzip the file and save it to dest path.</p>
|
<p>Unzip the file and save it to dest path.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -420,6 +461,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func UnZip(zipFile string, destPath string) error
|
func UnZip(zipFile string, destPath string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -431,14 +473,396 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ZipAppendEntry">ZipAppendEntry</span>
|
||||||
|
|
||||||
|
<p>Append a single file or directory by fpath to an existing zip file.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ZipAppendEntry(fpath string, destPath string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="CurrentPath">CurrentPath</span>
|
||||||
|
|
||||||
|
<p>return current absolute path.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CurrentPath() string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
absPath := CurrentPath()
|
||||||
|
fmt.Println(absPath)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsZipFile">IsZipFile</span>
|
||||||
|
|
||||||
|
<p>Checks if file is zip file or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsZipFile(filepath string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
isZip := IsZipFile("./zipfile.zip")
|
||||||
|
fmt.Println(isZip)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FileSize">FileSize</span>
|
||||||
|
|
||||||
|
<p>Returns file size in bytes.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func FileSize(path string) (int64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
size, err := fileutil.FileSize("./testdata/test.txt")
|
||||||
|
|
||||||
|
fmt.Println(size)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 20
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="MTime">MTime</span>
|
||||||
|
|
||||||
|
<p>Returns file modified time(unix timestamp).</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func MTime(filepath string) (int64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mtime, err := fileutil.MTime("./testdata/test.txt")
|
||||||
|
|
||||||
|
fmt.Println(mtime)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1682391110
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Sha">Sha</span>
|
||||||
|
|
||||||
|
<p>returns file sha value, param `shaType` should be 1, 256 or 512.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha(filepath string, shaType ...int) (string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sha1, err := fileutil.Sha("./testdata/test.txt", 1)
|
||||||
|
sha256, _ := fileutil.Sha("./testdata/test.txt", 256)
|
||||||
|
sha512, _ := fileutil.Sha("./testdata/test.txt", 512)
|
||||||
|
|
||||||
|
fmt.Println(sha1)
|
||||||
|
fmt.Println(sha256)
|
||||||
|
fmt.Println(sha512)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// dda3cf10c5a6ff6c6659a497bf7261b287af2bc7
|
||||||
|
// aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35
|
||||||
|
// d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ReadCsvFile">ReadCsvFile</span>
|
||||||
|
|
||||||
|
<p>Reads file content into slice.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReadCsvFile(filepath string) ([][]string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
content, err := fileutil.ReadCsvFile("./testdata/test.csv")
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="WriteCsvFile">WriteCsvFile</span>
|
||||||
|
|
||||||
|
<p>Write content to target csv file.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func WriteCsvFile(filepath string, records [][]string, append bool) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := [][]string{
|
||||||
|
{"Lili", "22", "female"},
|
||||||
|
{"Jim", "21", "male"},
|
||||||
|
}
|
||||||
|
err := WriteCsvFile("./testdata/test2.csv", data, false)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
content, _ := ReadCsvFile("./testdata/test2.csv")
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// <nil>
|
||||||
|
// [[Lili 22 female] [Jim 21 male]]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||||
|
|
||||||
|
<p>Writes bytes to target file.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func WriteBytesToFile(filepath string, content []byte) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
filepath := "./bytes.txt"
|
||||||
|
|
||||||
|
file, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := fileutil.ReadFileToString(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(filepath)
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="WriteStringToFile">WriteStringToFile</span>
|
||||||
|
|
||||||
|
<p>Writes string to target file.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func WriteStringToFile(filepath string, content string, append bool) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
filepath := "./test.txt"
|
||||||
|
|
||||||
|
file, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = fileutil.WriteStringToFile(filepath, "hello", true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := fileutil.ReadFileToString(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(filepath)
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ReadFile">ReadFile</span>
|
||||||
|
|
||||||
|
<p>Read File/URL</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;"> </span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
reader, fn, err := 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
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
# Fileutil
|
# Fileutil
|
||||||
fileutil包支持文件基本操作。
|
|
||||||
|
fileutil 包支持文件基本操作。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
|
[https://github.com/duke-git/lancet/blob/v1/fileutil/file.go](https://github.com/duke-git/lancet/blob/v1/fileutil/file.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法:
|
## 用法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/fileutil"
|
"github.com/duke-git/lancet/fileutil"
|
||||||
@@ -19,29 +21,40 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
- [ClearFile](#ClearFile)
|
|
||||||
- [CreateFile](#CreateFile)
|
|
||||||
- [CopyFile](#CopyFile)
|
|
||||||
- [FileMode](#FileMode)
|
|
||||||
- [MiMeType](#MiMeType)
|
|
||||||
- [IsExist](#IsExist)
|
|
||||||
- [IsLink](#IsLink)
|
|
||||||
- [IsDir](#IsDir)
|
|
||||||
|
|
||||||
- [ListFileNames](#ListFileNames)
|
- [ClearFile](#ClearFile)
|
||||||
- [RemoveFile](#RemoveFile)
|
- [CreateFile](#CreateFile)
|
||||||
- [ReadFileToString](#ReadFileToString)
|
- [CreateDir](#CreateDir)
|
||||||
- [ReadFileByLine](#ReadFileByLine)
|
- [CopyFile](#CopyFile)
|
||||||
- [Zip](#Zip)
|
- [FileMode](#FileMode)
|
||||||
- [UnZip](#UnZip)
|
- [MiMeType](#MiMeType)
|
||||||
|
- [IsExist](#IsExist)
|
||||||
|
- [IsLink](#IsLink)
|
||||||
|
- [IsDir](#IsDir)画
|
||||||
|
- [ListFileNames](#ListFileNames)
|
||||||
|
- [RemoveFile](#RemoveFile)
|
||||||
|
- [ReadFileToString](#ReadFileToString)
|
||||||
|
- [ReadFileByLine](#ReadFileByLine)
|
||||||
|
- [Zip](#Zip)
|
||||||
|
- [UnZip](#UnZip)
|
||||||
|
- [ZipAppendEntry](#ZipAppendEntry)
|
||||||
|
- [CurrentPath](#CurrentPath)
|
||||||
|
- [IsZipFile](#IsZipFile)
|
||||||
|
- [FileSize](#FileSize)
|
||||||
|
- [MTime](#MTime)
|
||||||
|
- [Sha](#Sha)
|
||||||
|
- [ReadCsvFile](#ReadCsvFile)
|
||||||
|
- [WriteCsvFile](#WriteCsvFile)
|
||||||
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
|
- [ReadFile](#ReadFile)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ClearFile">ClearFile</span>
|
### <span id="ClearFile">ClearFile</span>
|
||||||
|
|
||||||
<p>清空文件内容</p>
|
<p>清空文件内容</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -49,6 +62,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func ClearFile(path string) error
|
func ClearFile(path string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -67,7 +81,34 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="CreateDir">CreateDir</span>
|
||||||
|
|
||||||
|
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CreateDir(absPath string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := fileutil.CreateDir("/a/")
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="CreateFile">CreateFile</span>
|
### <span id="CreateFile">CreateFile</span>
|
||||||
|
|
||||||
<p>创建文件,创建成功返回true, 否则返回false</p>
|
<p>创建文件,创建成功返回true, 否则返回false</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -75,6 +116,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func CreateFile(path string) bool
|
func CreateFile(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -91,8 +133,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="CopyFile">CopyFile</span>
|
### <span id="CopyFile">CopyFile</span>
|
||||||
|
|
||||||
<p>拷贝文件,会覆盖原有的拷贝文件</p>
|
<p>拷贝文件,会覆盖原有的拷贝文件</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -100,6 +142,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func CopyFile(srcFilePath string, dstFilePath string) error
|
func CopyFile(srcFilePath string, dstFilePath string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -112,15 +155,14 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
|
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="FileMode">FileMode</span>
|
### <span id="FileMode">FileMode</span>
|
||||||
|
|
||||||
<p>获取文件mode信息</p>
|
<p>获取文件mode信息</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -128,6 +170,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func FileMode(path string) (fs.FileMode, error)
|
func FileMode(path string) (fs.FileMode, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -140,16 +183,15 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
mode, err := fileutil.FileMode("./test.txt")
|
mode, err := fileutil.FileMode("./test.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
fmt.Println(mode)
|
fmt.Println(mode)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="MiMeType">MiMeType</span>
|
### <span id="MiMeType">MiMeType</span>
|
||||||
|
|
||||||
<p>获取文件mime类型, 'file'参数的类型必须是string或者*os.File</p>
|
<p>获取文件mime类型, 'file'参数的类型必须是string或者*os.File</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -157,6 +199,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func MiMeType(file interface{}) string
|
func MiMeType(file interface{}) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -178,10 +221,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsExist">IsExist</span>
|
### <span id="IsExist">IsExist</span>
|
||||||
|
|
||||||
<p>判断文件或目录是否存在</p>
|
<p>判断文件或目录是否存在</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -189,6 +230,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsExist(path string) bool
|
func IsExist(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -206,9 +248,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsLink">IsLink</span>
|
### <span id="IsLink">IsLink</span>
|
||||||
|
|
||||||
<p>判断文件是否是符号链接</p>
|
<p>判断文件是否是符号链接</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -216,6 +257,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsLink(path string) bool
|
func IsLink(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -232,16 +274,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsDir">IsDir</span>
|
### <span id="IsDir">IsDir</span>
|
||||||
|
|
||||||
<p>判断目录是否存在</p>
|
<p>判断目录是否存在</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func IsDir(path string) bool
|
func IsDir(path string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -261,9 +303,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ListFileNames">ListFileNames</span>
|
### <span id="ListFileNames">ListFileNames</span>
|
||||||
|
|
||||||
<p>返回目录下所有文件名</p>
|
<p>返回目录下所有文件名</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -271,6 +312,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ListFileNames(path string) ([]string, error)
|
func ListFileNames(path string) ([]string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -287,9 +329,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RemoveFile">RemoveFile</span>
|
### <span id="RemoveFile">RemoveFile</span>
|
||||||
|
|
||||||
<p>删除文件</p>
|
<p>删除文件</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -297,6 +338,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RemoveFile(path string) error
|
func RemoveFile(path string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -310,13 +352,13 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
err := fileutil.RemoveFile("./test.txt")
|
err := fileutil.RemoveFile("./test.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="ReadFileToString">ReadFileToString</span>
|
### <span id="ReadFileToString">ReadFileToString</span>
|
||||||
|
|
||||||
<p>读取文件内容并返回字符串</p>
|
<p>读取文件内容并返回字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -324,6 +366,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ReadFileToString(path string) (string, error)
|
func ReadFileToString(path string) (string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -337,19 +380,18 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
path := "./test.txt"
|
path := "./test.txt"
|
||||||
fileutil.CreateFile(path)
|
fileutil.CreateFile(path)
|
||||||
|
|
||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
f.WriteString("hello world")
|
f.WriteString("hello world")
|
||||||
|
|
||||||
content, _ := fileutil.ReadFileToString(path)
|
content, _ := fileutil.ReadFileToString(path)
|
||||||
fmt.Println(content) //hello world
|
fmt.Println(content) //hello world
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ReadFileByLine">ReadFileByLine</span>
|
### <span id="ReadFileByLine">ReadFileByLine</span>
|
||||||
|
|
||||||
<p>按行读取文件内容,返回字符串切片包含每一行</p>
|
<p>按行读取文件内容,返回字符串切片包含每一行</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -357,6 +399,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func ReadFileByLine(path string)([]string, error)
|
func ReadFileByLine(path string)([]string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -370,20 +413,19 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
path := "./text.txt"
|
path := "./text.txt"
|
||||||
fileutil.CreateFile(path)
|
fileutil.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")
|
f.WriteString("hello\nworld")
|
||||||
|
|
||||||
contents, _ := fileutil.ReadFileByLine(path)
|
contents, _ := fileutil.ReadFileByLine(path)
|
||||||
fmt.Println(contents) //[]string{"hello", "world"}
|
fmt.Println(contents) //[]string{"hello", "world"}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Zip">Zip</span>
|
### <span id="Zip">Zip</span>
|
||||||
|
|
||||||
<p>zip压缩文件, fpath参数可以是文件或目录</p>
|
<p>zip压缩文件, fpath参数可以是文件或目录</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -391,6 +433,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Zip(fpath string, destPath string) error
|
func Zip(fpath string, destPath string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -402,24 +445,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := fileutil.Zip("./test.txt", "./test.zip")
|
err := fileutil.Zip("./test.txt", "./test.zip")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="UnZip">UnZip</span>
|
### <span id="UnZip">UnZip</span>
|
||||||
|
|
||||||
<p>zip解压缩文件并保存在目录中</p>
|
<p>zip解压缩文件并保存在目录中</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func UnZip(zipFile string, destPath string) error
|
func UnZip(zipFile string, destPath string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -431,14 +473,396 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ZipAppendEntry">ZipAppendEntry</span>
|
||||||
|
|
||||||
|
<p>通过将单个文件或目录追加到现有的zip文件</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ZipAppendEntry(fpath string, destPath string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="CurrentPath">CurrentPath</span>
|
||||||
|
|
||||||
|
<p>返回当前位置的绝对路径。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CurrentPath() string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
absPath := CurrentPath()
|
||||||
|
fmt.Println(absPath)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsZipFile">IsZipFile</span>
|
||||||
|
|
||||||
|
<p>判断文件是否是zip压缩文件。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsZipFile(filepath string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
isZip := IsZipFile("./zipfile.zip")
|
||||||
|
fmt.Println(isZip)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FileSize">FileSize</span>
|
||||||
|
|
||||||
|
<p>返回文件字节大小。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func FileSize(path string) (int64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
size, err := fileutil.FileSize("./testdata/test.txt")
|
||||||
|
|
||||||
|
fmt.Println(size)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 20
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="MTime">MTime</span>
|
||||||
|
|
||||||
|
<p>返回文件修改时间(unix timestamp).</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func MTime(filepath string) (int64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mtime, err := fileutil.MTime("./testdata/test.txt")
|
||||||
|
|
||||||
|
fmt.Println(mtime)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1682391110
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Sha">Sha</span>
|
||||||
|
|
||||||
|
<p>返回文件sha值,参数`shaType` 应传值为: 1, 256,512.</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha(filepath string, shaType ...int) (string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sha1, err := fileutil.Sha("./testdata/test.txt", 1)
|
||||||
|
sha256, _ := fileutil.Sha("./testdata/test.txt", 256)
|
||||||
|
sha512, _ := fileutil.Sha("./testdata/test.txt", 512)
|
||||||
|
|
||||||
|
fmt.Println(sha1)
|
||||||
|
fmt.Println(sha256)
|
||||||
|
fmt.Println(sha512)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// dda3cf10c5a6ff6c6659a497bf7261b287af2bc7
|
||||||
|
// aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35
|
||||||
|
// d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ReadCsvFile">ReadCsvFile</span>
|
||||||
|
|
||||||
|
<p>读取csv文件内容到切片</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReadCsvFile(filepath string) ([][]string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
content, err := fileutil.ReadCsvFile("./testdata/test.csv")
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="WriteCsvFile">WriteCsvFile</span>
|
||||||
|
|
||||||
|
<p>向csv文件写入内容。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func WriteCsvFile(filepath string, records [][]string, append bool) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := [][]string{
|
||||||
|
{"Lili", "22", "female"},
|
||||||
|
{"Jim", "21", "male"},
|
||||||
|
}
|
||||||
|
err := WriteCsvFile("./testdata/test2.csv", data, false)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
content, _ := ReadCsvFile("./testdata/test2.csv")
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// <nil>
|
||||||
|
// [[Lili 22 female] [Jim 21 male]]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||||
|
|
||||||
|
<p>将bytes写入文件。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func WriteBytesToFile(filepath string, content []byte) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
filepath := "./bytes.txt"
|
||||||
|
|
||||||
|
file, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := fileutil.ReadFileToString(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(filepath)
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="WriteStringToFile">WriteStringToFile</span>
|
||||||
|
|
||||||
|
<p>将字符串写入文件。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func WriteStringToFile(filepath string, content string, append bool) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
filepath := "./test.txt"
|
||||||
|
|
||||||
|
file, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = fileutil.WriteStringToFile(filepath, "hello", true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := fileutil.ReadFileToString(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(filepath)
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ReadFile">ReadFile</span>
|
||||||
|
|
||||||
|
<p>读取文件或者URL</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;"></span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
reader, fn, err := 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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
# Formatter
|
# Formatter
|
||||||
|
|
||||||
formatter contains some functions for data formatting.
|
formatter contains some functions for data formatting.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
[https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go](https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/formatter"
|
"github.com/duke-git/lancet/formatter"
|
||||||
@@ -19,23 +21,30 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [Comma](#Comma)
|
|
||||||
|
- [Comma](#Comma)
|
||||||
|
- [Pretty](#Pretty)
|
||||||
|
- [PrettyToWriter](#PrettyToWriter)
|
||||||
|
- [DecimalBytes](#DecimalBytes)
|
||||||
|
- [BinaryBytes](#BinaryBytes)
|
||||||
|
- [ParseDecimalBytes](#ParseDecimalBytes)
|
||||||
|
- [ParseBinaryBytes](#ParseBinaryBytes)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <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 number by every 3 numbers from right. ahead by symbol char.
|
||||||
Param should be number or numberic string.</p>
|
Param should be number or numberic string.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Comma(v interface{}, symbol string) string
|
func Comma(value interface{}, symbol string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -51,3 +60,241 @@ func main() {
|
|||||||
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pretty">Pretty</span>
|
||||||
|
|
||||||
|
<p>Pretty data to JSON string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Pretty(v interface{}) (string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
|
||||||
|
result2, _ := formatter.Pretty(map[string]int{"a": 1})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [
|
||||||
|
// "a",
|
||||||
|
// "b",
|
||||||
|
// "c"
|
||||||
|
// ]
|
||||||
|
// {
|
||||||
|
// "a": 1
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="PrettyToWriter">PrettyToWriter</span>
|
||||||
|
|
||||||
|
<p>Pretty encode data to writer.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PrettyToWriter(v interface{}, out io.Writer) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type User struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Aage uint `json:"age"`
|
||||||
|
}
|
||||||
|
user := User{Name: "King", Aage: 10000}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := formatter.PrettyToWriter(user, buf)
|
||||||
|
|
||||||
|
fmt.Println(buf)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// {
|
||||||
|
// "name": "King",
|
||||||
|
// "age": 10000
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="DecimalBytes">DecimalBytes</span>
|
||||||
|
|
||||||
|
<p>Returns a human readable byte size under decimal standard (base 1000). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func DecimalBytes(size float64, precision ...int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := formatter.DecimalBytes(1000)
|
||||||
|
result2 := formatter.DecimalBytes(1024)
|
||||||
|
result3 := formatter.DecimalBytes(1234567)
|
||||||
|
result4 := formatter.DecimalBytes(1234567, 3)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1KB
|
||||||
|
// 1.024KB
|
||||||
|
// 1.2346MB
|
||||||
|
// 1.235MB
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="BinaryBytes">BinaryBytes</span>
|
||||||
|
|
||||||
|
<p>Returns a human readable byte size under binary standard (base 1024). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func BinaryBytes(size float64, precision ...int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := formatter.BinaryBytes(1024)
|
||||||
|
result2 := formatter.BinaryBytes(1024 * 1024)
|
||||||
|
result3 := formatter.BinaryBytes(1234567)
|
||||||
|
result4 := formatter.BinaryBytes(1234567, 2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1KiB
|
||||||
|
// 1MiB
|
||||||
|
// 1.1774MiB
|
||||||
|
// 1.18MiB
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
|
||||||
|
|
||||||
|
<p>Returns the human readable bytes size string into the amount it represents(base 1000).</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ParseDecimalBytes(size string) (uint64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1, _ := formatter.ParseDecimalBytes("12")
|
||||||
|
result2, _ := formatter.ParseDecimalBytes("12k")
|
||||||
|
result3, _ := formatter.ParseDecimalBytes("12 Kb")
|
||||||
|
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 12
|
||||||
|
// 12000
|
||||||
|
// 12000
|
||||||
|
// 12200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
|
||||||
|
|
||||||
|
<p>Returns the human readable bytes size string into the amount it represents(base 1024).</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ParseBinaryBytes(size string) (uint64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1, _ := formatter.ParseBinaryBytes("12")
|
||||||
|
result2, _ := formatter.ParseBinaryBytes("12ki")
|
||||||
|
result3, _ := formatter.ParseBinaryBytes("12 KiB")
|
||||||
|
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 12
|
||||||
|
// 12288
|
||||||
|
// 12288
|
||||||
|
// 12492
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
# Formatter
|
# Formatter
|
||||||
formatter格式化器包含一些数据格式化处理方法。
|
|
||||||
|
formatter 格式化器包含一些数据格式化处理方法。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
[https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go](https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法:
|
## 用法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/formatter"
|
"github.com/duke-git/lancet/formatter"
|
||||||
@@ -19,15 +21,21 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
- [Comma](#Comma)
|
|
||||||
|
- [Comma](#Comma)
|
||||||
|
- [Pretty](#Pretty)
|
||||||
|
- [PrettyToWriter](#PrettyToWriter)
|
||||||
|
- [DecimalBytes](#DecimalBytes)
|
||||||
|
- [BinaryBytes](#BinaryBytes)
|
||||||
|
- [ParseDecimalBytes](#ParseDecimalBytes)
|
||||||
|
- [ParseBinaryBytes](#ParseBinaryBytes)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Comma">Comma</span>
|
### <span id="Comma">Comma</span>
|
||||||
|
|
||||||
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
|
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -35,6 +43,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func Comma(v interface{}, symbol string) string
|
func Comma(v interface{}, symbol string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -50,3 +59,241 @@ func main() {
|
|||||||
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pretty">Pretty</span>
|
||||||
|
|
||||||
|
<p>返回pretty JSON字符串.</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Pretty(v interface{}) (string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
|
||||||
|
result2, _ := formatter.Pretty(map[string]int{"a": 1})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [
|
||||||
|
// "a",
|
||||||
|
// "b",
|
||||||
|
// "c"
|
||||||
|
// ]
|
||||||
|
// {
|
||||||
|
// "a": 1
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="PrettyToWriter">PrettyToWriter</span>
|
||||||
|
|
||||||
|
<p>Pretty encode数据到writer。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PrettyToWriter(v interface{}, out io.Writer) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type User struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Aage uint `json:"age"`
|
||||||
|
}
|
||||||
|
user := User{Name: "King", Aage: 10000}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := formatter.PrettyToWriter(user, buf)
|
||||||
|
|
||||||
|
fmt.Println(buf)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// {
|
||||||
|
// "name": "King",
|
||||||
|
// "age": 10000
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="DecimalBytes">DecimalBytes</span>
|
||||||
|
|
||||||
|
<p>返回十进制标准(以1000为基数)下的可读字节单位字符串。precision参数指定小数点后的位数,默认为4。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func DecimalBytes(size float64, precision ...int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := formatter.DecimalBytes(1000)
|
||||||
|
result2 := formatter.DecimalBytes(1024)
|
||||||
|
result3 := formatter.DecimalBytes(1234567)
|
||||||
|
result4 := formatter.DecimalBytes(1234567, 3)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1KB
|
||||||
|
// 1.024KB
|
||||||
|
// 1.2346MB
|
||||||
|
// 1.235MB
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="BinaryBytes">BinaryBytes</span>
|
||||||
|
|
||||||
|
<p>返回binary标准(以1024为基数)下的可读字节单位字符串。precision参数指定小数点后的位数,默认为4。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func BinaryBytes(size float64, precision ...int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := formatter.BinaryBytes(1024)
|
||||||
|
result2 := formatter.BinaryBytes(1024 * 1024)
|
||||||
|
result3 := formatter.BinaryBytes(1234567)
|
||||||
|
result4 := formatter.BinaryBytes(1234567, 2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1KiB
|
||||||
|
// 1MiB
|
||||||
|
// 1.1774MiB
|
||||||
|
// 1.18MiB
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
|
||||||
|
|
||||||
|
<p>将字节单位字符串转换成其所表示的字节数(以1000为基数)。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ParseDecimalBytes(size string) (uint64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1, _ := formatter.ParseDecimalBytes("12")
|
||||||
|
result2, _ := formatter.ParseDecimalBytes("12k")
|
||||||
|
result3, _ := formatter.ParseDecimalBytes("12 Kb")
|
||||||
|
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 12
|
||||||
|
// 12000
|
||||||
|
// 12000
|
||||||
|
// 12200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
|
||||||
|
|
||||||
|
<p>将字节单位字符串转换成其所表示的字节数(以1024为基数)。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ParseBinaryBytes(size string) (uint64, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/formatter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1, _ := formatter.ParseBinaryBytes("12")
|
||||||
|
result2, _ := formatter.ParseBinaryBytes("12ki")
|
||||||
|
result3, _ := formatter.ParseBinaryBytes("12 KiB")
|
||||||
|
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 12
|
||||||
|
// 12288
|
||||||
|
// 12288
|
||||||
|
// 12492
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
258
docs/function.md
258
docs/function.md
@@ -1,16 +1,18 @@
|
|||||||
# Function
|
# Function
|
||||||
|
|
||||||
Package function can control the flow of function execution and support part of functional programming.
|
Package function can control the flow of function execution and support part of functional programming.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
[https://github.com/duke-git/lancet/blob/v1/function/function.go](https://github.com/duke-git/lancet/blob/v1/function/function.go)
|
||||||
[https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
[https://github.com/duke-git/lancet/blob/v1/function/watcher.go](https://github.com/duke-git/lancet/blob/v1/function/watcher.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/function"
|
"github.com/duke-git/lancet/function"
|
||||||
@@ -20,21 +22,23 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [After](#After)
|
|
||||||
- [Before](#Before)
|
- [After](#After)
|
||||||
- [Curry](#Curry)
|
- [Before](#Before)
|
||||||
- [Compose](#Compose)
|
- [Curry](#Curry)
|
||||||
- [Debounced](#Debounced)
|
- [Compose](#Compose)
|
||||||
- [Delay](#Delay)
|
- [Debounced](#Debounced)
|
||||||
- [Watcher](#Watcher)
|
- [Delay](#Delay)
|
||||||
|
- [Pipeline](#Pipeline)
|
||||||
|
- [Schedule](#Schedule)
|
||||||
|
- [Watcher](#Watcher)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="After">After</span>
|
### <span id="After">After</span>
|
||||||
|
|
||||||
<p>Creates a function that invokes given func once it's called n or more times.</p>
|
<p>Creates a function that invokes given func once it's called n or more times.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -42,6 +46,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -53,33 +58,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
arr := []string{"a", "b"}
|
arr := []string{"a", "b"}
|
||||||
f := function.After(len(arr), func(i int) int {
|
f := function.After(len(arr), func(i int) int {
|
||||||
fmt.Println("last print")
|
fmt.Println("last print")
|
||||||
return i
|
return i
|
||||||
})
|
})
|
||||||
|
|
||||||
type cb func(args ...interface{}) []reflect.Value
|
type cb func(args ...interface{}) []reflect.Value
|
||||||
print := func(i int, s string, fn cb) {
|
print := func(i int, s string, fn cb) {
|
||||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||||
fn(i)
|
fn(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("arr is", arr)
|
fmt.Println("arr is", arr)
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
print(i, arr[i], f)
|
print(i, arr[i], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
//output:
|
//output:
|
||||||
// arr is [a b]
|
// arr is [a b]
|
||||||
// arr[0] is a
|
// arr[0] is a
|
||||||
// arr[1] is b
|
// arr[1] is b
|
||||||
// last print
|
// last print
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Before">Before</span>
|
### <span id="Before">Before</span>
|
||||||
|
|
||||||
<p>creates a function that invokes func once it's called less than n times.</p>
|
<p>creates a function that invokes func once it's called less than n times.</p>
|
||||||
@@ -89,6 +92,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -103,29 +107,27 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
assert := internal.NewAssert(t, "TestBefore")
|
assert := internal.NewAssert(t, "TestBefore")
|
||||||
|
|
||||||
arr := []string{"a", "b", "c", "d", "e"}
|
arr := []string{"a", "b", "c", "d", "e"}
|
||||||
f := function.Before(3, func(i int) int {
|
f := function.Before(3, func(i int) int {
|
||||||
return i
|
return i
|
||||||
})
|
})
|
||||||
|
|
||||||
var res []int64
|
var res []int64
|
||||||
type cb func(args ...interface{}) []reflect.Value
|
type cb func(args ...interface{}) []reflect.Value
|
||||||
appendStr := func(i int, s string, fn cb) {
|
appendStr := func(i int, s string, fn cb) {
|
||||||
v := fn(i)
|
v := fn(i)
|
||||||
res = append(res, v[0].Int())
|
res = append(res, v[0].Int())
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
appendStr(i, arr[i], f)
|
appendStr(i, arr[i], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := []int64{0, 1, 2, 2, 2}
|
expected := []int64{0, 1, 2, 2, 2}
|
||||||
assert.Equal(expected, res)
|
assert.Equal(expected, res)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Curry">Curry</span>
|
### <span id="Curry">Curry</span>
|
||||||
|
|
||||||
<p>Make a curry function.</p>
|
<p>Make a curry function.</p>
|
||||||
@@ -136,6 +138,7 @@ func main() {
|
|||||||
type Fn func(...interface{}) interface{}
|
type Fn func(...interface{}) interface{}
|
||||||
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
|
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -148,19 +151,17 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
add := func(a, b int) int {
|
add := func(a, b int) int {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
var addCurry function.Fn = func(values ...interface{}) interface{} {
|
var addCurry function.Fn = func(values ...interface{}) interface{} {
|
||||||
return add(values[0].(int), values[1].(int))
|
return add(values[0].(int), values[1].(int))
|
||||||
}
|
}
|
||||||
add1 := addCurry.Curry(1)
|
add1 := addCurry.Curry(1)
|
||||||
result := add1(2)
|
result := add1(2)
|
||||||
fmt.Println(result) //3
|
fmt.Println(result) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Compose">Compose</span>
|
### <span id="Compose">Compose</span>
|
||||||
|
|
||||||
<p>Compose the function list from right to left, then return the composed function.</p>
|
<p>Compose the function list from right to left, then return the composed function.</p>
|
||||||
@@ -170,6 +171,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
|
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -182,21 +184,19 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
add1 := func(v ...interface{}) interface{} {
|
add1 := func(v ...interface{}) interface{} {
|
||||||
return v[0].(int) + 1
|
return v[0].(int) + 1
|
||||||
}
|
}
|
||||||
add2 := func(v ...interface{}) interface{} {
|
add2 := func(v ...interface{}) interface{} {
|
||||||
return v[0].(int) + 2
|
return v[0].(int) + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
add3 := function.Compose(add1, add2)
|
add3 := function.Compose(add1, add2)
|
||||||
result := add3(1)
|
result := add3(1)
|
||||||
|
|
||||||
fmt.Println(result) //4
|
fmt.Println(result) //4
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Debounced">Debounced</span>
|
### <span id="Debounced">Debounced</span>
|
||||||
|
|
||||||
<p>Creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.</p>
|
<p>Creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.</p>
|
||||||
@@ -206,6 +206,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Debounced(fn func(), duration time.Duration) func()
|
func Debounced(fn func(), duration time.Duration) func()
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -218,27 +219,25 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
count := 0
|
count := 0
|
||||||
add := func() {
|
add := func() {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
|
||||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
fmt.Println(count) //1
|
fmt.Println(count) //1
|
||||||
|
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
fmt.Println(count) //2
|
fmt.Println(count) //2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Delay">Delay</span>
|
### <span id="Delay">Delay</span>
|
||||||
|
|
||||||
<p>Invoke function after delayed time.</p>
|
<p>Invoke function after delayed time.</p>
|
||||||
@@ -248,6 +247,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Delay(delay time.Duration, fn interface{}, args ...interface{})
|
func Delay(delay time.Duration, fn interface{}, args ...interface{})
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -259,15 +259,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var print = func(s string) {
|
var print = func(s string) {
|
||||||
fmt.Println(count) //test delay
|
fmt.Println(count) //test delay
|
||||||
}
|
}
|
||||||
function.Delay(2*time.Second, print, "test delay")
|
function.Delay(2*time.Second, print, "test delay")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Schedule">Schedule</span>
|
### <span id="Schedule">Schedule</span>
|
||||||
|
|
||||||
<p>Invoke function every duration time, until close the returned bool chan.</p>
|
<p>Invoke function every duration time, until close the returned bool chan.</p>
|
||||||
@@ -277,6 +275,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
|
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -289,19 +288,60 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var res []string
|
var res []string
|
||||||
appendStr := func(s string) {
|
appendStr := func(s string) {
|
||||||
res = append(res, s)
|
res = append(res, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
close(stop)
|
close(stop)
|
||||||
|
|
||||||
fmt.Println(res) //[* * * * *]
|
fmt.Println(res) //[* * * * *]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pipeline">Pipeline</span>
|
||||||
|
|
||||||
|
<p>Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||||
|
the functions one by one.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{}
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
addOne := func(x interface{}) interface{} {
|
||||||
|
return x.(int) + 1
|
||||||
|
}
|
||||||
|
double := func(x interface{}) interface{} {
|
||||||
|
return 2 * x.(int)
|
||||||
|
}
|
||||||
|
square := func(x interface{}) interface{} {
|
||||||
|
return x.(int) * x.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := function.Pipeline(addOne, double, square)
|
||||||
|
|
||||||
|
result := fn(2)
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 36
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Watcher">Watcher</span>
|
### <span id="Watcher">Watcher</span>
|
||||||
|
|
||||||
@@ -311,15 +351,16 @@ func main() {
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
type Watcher struct {
|
type Watcher struct {
|
||||||
startTime int64
|
startTime int64
|
||||||
stopTime int64
|
stopTime int64
|
||||||
excuting bool
|
excuting bool
|
||||||
}
|
}
|
||||||
func (w *Watcher) Start() //start the watcher
|
func (w *Watcher) Start() //start the watcher
|
||||||
func (w *Watcher) Stop() //stop the watcher
|
func (w *Watcher) Stop() //stop the watcher
|
||||||
func (w *Watcher) Reset() //reset the watcher
|
func (w *Watcher) Reset() //reset the watcher
|
||||||
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -332,33 +373,30 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
w := &function.Watcher{}
|
w := &function.Watcher{}
|
||||||
w.Start()
|
w.Start()
|
||||||
|
|
||||||
longRunningTask()
|
longRunningTask()
|
||||||
|
|
||||||
fmt.Println(w.excuting) //true
|
fmt.Println(w.excuting) //true
|
||||||
|
|
||||||
w.Stop()
|
w.Stop()
|
||||||
|
|
||||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||||
fmt.Println(eapsedTime)
|
fmt.Println(eapsedTime)
|
||||||
|
|
||||||
w.Reset()
|
w.Reset()
|
||||||
|
|
||||||
fmt.Println(w.excuting) //false
|
fmt.Println(w.excuting) //false
|
||||||
|
|
||||||
fmt.Println(w.startTime) //0
|
fmt.Println(w.startTime) //0
|
||||||
fmt.Println(w.stopTime) //0
|
fmt.Println(w.stopTime) //0
|
||||||
}
|
}
|
||||||
|
|
||||||
func longRunningTask() {
|
func longRunningTask() {
|
||||||
var slice []int64
|
var slice []int64
|
||||||
for i := 0; i < 10000000; i++ {
|
for i := 0; i < 10000000; i++ {
|
||||||
slice = append(slice, int64(i))
|
slice = append(slice, int64(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
# Function
|
# Function
|
||||||
function函数包控制函数执行流程,包含部分函数式编程。
|
|
||||||
|
function 函数包控制函数执行流程,包含部分函数式编程。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
[https://github.com/duke-git/lancet/blob/v1/function/function.go](https://github.com/duke-git/lancet/blob/v1/function/function.go)
|
||||||
[https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
[https://github.com/duke-git/lancet/blob/v1/function/watcher.go](https://github.com/duke-git/lancet/blob/v1/function/watcher.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法:
|
## 用法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/function"
|
"github.com/duke-git/lancet/function"
|
||||||
@@ -20,21 +22,23 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
- [After](#After)
|
|
||||||
- [Before](#Before)
|
- [After](#After)
|
||||||
- [Curry](#Curry)
|
- [Before](#Before)
|
||||||
- [Compose](#Compose)
|
- [Curry](#Curry)
|
||||||
- [Debounced](#Debounced)
|
- [Compose](#Compose)
|
||||||
- [Delay](#Delay)
|
- [Debounced](#Debounced)
|
||||||
- [Watcher](#Watcher)
|
- [Delay](#Delay)
|
||||||
|
- [Pipeline](#Pipeline)
|
||||||
|
- [Schedule](#Schedule)
|
||||||
|
- [Watcher](#Watcher)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="After">After</span>
|
### <span id="After">After</span>
|
||||||
|
|
||||||
<p>创建一个函数,当他被调用n或更多次之后将马上触发fn</p>
|
<p>创建一个函数,当他被调用n或更多次之后将马上触发fn</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -42,6 +46,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -53,33 +58,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
arr := []string{"a", "b"}
|
arr := []string{"a", "b"}
|
||||||
f := function.After(len(arr), func(i int) int {
|
f := function.After(len(arr), func(i int) int {
|
||||||
fmt.Println("last print")
|
fmt.Println("last print")
|
||||||
return i
|
return i
|
||||||
})
|
})
|
||||||
|
|
||||||
type cb func(args ...interface{}) []reflect.Value
|
type cb func(args ...interface{}) []reflect.Value
|
||||||
print := func(i int, s string, fn cb) {
|
print := func(i int, s string, fn cb) {
|
||||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||||
fn(i)
|
fn(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("arr is", arr)
|
fmt.Println("arr is", arr)
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
print(i, arr[i], f)
|
print(i, arr[i], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
//output:
|
//output:
|
||||||
// arr is [a b]
|
// arr is [a b]
|
||||||
// arr[0] is a
|
// arr[0] is a
|
||||||
// arr[1] is b
|
// arr[1] is b
|
||||||
// last print
|
// last print
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Before">Before</span>
|
### <span id="Before">Before</span>
|
||||||
|
|
||||||
<p>创建一个函数,调用次数不超过n次,之后再调用这个函数,将返回一次最后调用fn的结果</p>
|
<p>创建一个函数,调用次数不超过n次,之后再调用这个函数,将返回一次最后调用fn的结果</p>
|
||||||
@@ -89,6 +92,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -101,31 +105,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
assert := internal.NewAssert(t, "TestBefore")
|
assert := internal.NewAssert(t, "TestBefore")
|
||||||
|
|
||||||
arr := []string{"a", "b", "c", "d", "e"}
|
arr := []string{"a", "b", "c", "d", "e"}
|
||||||
f := function.Before(3, func(i int) int {
|
f := function.Before(3, func(i int) int {
|
||||||
return i
|
return i
|
||||||
})
|
})
|
||||||
|
|
||||||
var res []int64
|
var res []int64
|
||||||
type cb func(args ...interface{}) []reflect.Value
|
type cb func(args ...interface{}) []reflect.Value
|
||||||
appendStr := func(i int, s string, fn cb) {
|
appendStr := func(i int, s string, fn cb) {
|
||||||
v := fn(i)
|
v := fn(i)
|
||||||
res = append(res, v[0].Int())
|
res = append(res, v[0].Int())
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
appendStr(i, arr[i], f)
|
appendStr(i, arr[i], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := []int64{0, 1, 2, 2, 2}
|
expected := []int64{0, 1, 2, 2, 2}
|
||||||
assert.Equal(expected, res)
|
assert.Equal(expected, res)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Curry">Curry</span>
|
### <span id="Curry">Curry</span>
|
||||||
|
|
||||||
<p>创建一个柯里化的函数</p>
|
<p>创建一个柯里化的函数</p>
|
||||||
@@ -136,6 +138,7 @@ func main() {
|
|||||||
type Fn func(...interface{}) interface{}
|
type Fn func(...interface{}) interface{}
|
||||||
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
|
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -147,20 +150,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
add := func(a, b int) int {
|
add := func(a, b int) int {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
var addCurry function.Fn = func(values ...interface{}) interface{} {
|
var addCurry function.Fn = func(values ...interface{}) interface{} {
|
||||||
return add(values[0].(int), values[1].(int))
|
return add(values[0].(int), values[1].(int))
|
||||||
}
|
}
|
||||||
add1 := addCurry.Curry(1)
|
add1 := addCurry.Curry(1)
|
||||||
result := add1(2)
|
result := add1(2)
|
||||||
fmt.Println(result) //3
|
fmt.Println(result) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Compose">Compose</span>
|
### <span id="Compose">Compose</span>
|
||||||
|
|
||||||
<p>从右至左组合函数列表fnList, 返回组合后的函数</p>
|
<p>从右至左组合函数列表fnList, 返回组合后的函数</p>
|
||||||
@@ -170,6 +171,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
|
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -181,22 +183,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
add1 := func(v ...interface{}) interface{} {
|
add1 := func(v ...interface{}) interface{} {
|
||||||
return v[0].(int) + 1
|
return v[0].(int) + 1
|
||||||
}
|
}
|
||||||
add2 := func(v ...interface{}) interface{} {
|
add2 := func(v ...interface{}) interface{} {
|
||||||
return v[0].(int) + 2
|
return v[0].(int) + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
add3 := function.Compose(add1, add2)
|
add3 := function.Compose(add1, add2)
|
||||||
result := add3(1)
|
result := add3(1)
|
||||||
|
|
||||||
fmt.Println(result) //4
|
fmt.Println(result) //4
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Debounced">Debounced</span>
|
### <span id="Debounced">Debounced</span>
|
||||||
|
|
||||||
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
||||||
@@ -206,6 +206,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Debounced(fn func(), duration time.Duration) func()
|
func Debounced(fn func(), duration time.Duration) func()
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -217,28 +218,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
count := 0
|
count := 0
|
||||||
add := func() {
|
add := func() {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
|
||||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
fmt.Println(count) //1
|
fmt.Println(count) //1
|
||||||
|
|
||||||
function.debouncedAdd()
|
function.debouncedAdd()
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
fmt.Println(count) //2
|
fmt.Println(count) //2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Delay">Delay</span>
|
### <span id="Delay">Delay</span>
|
||||||
|
|
||||||
<p>延迟delay时间后调用函数</p>
|
<p>延迟delay时间后调用函数</p>
|
||||||
@@ -248,6 +247,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Delay(delay time.Duration, fn interface{}, args ...interface{})
|
func Delay(delay time.Duration, fn interface{}, args ...interface{})
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -259,15 +259,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var print = func(s string) {
|
var print = func(s string) {
|
||||||
fmt.Println(count) //test delay
|
fmt.Println(count) //test delay
|
||||||
}
|
}
|
||||||
function.Delay(2*time.Second, print, "test delay")
|
function.Delay(2*time.Second, print, "test delay")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Schedule">Schedule</span>
|
### <span id="Schedule">Schedule</span>
|
||||||
|
|
||||||
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
|
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
|
||||||
@@ -277,6 +275,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
|
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -289,19 +288,59 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var res []string
|
var res []string
|
||||||
appendStr := func(s string) {
|
appendStr := func(s string) {
|
||||||
res = append(res, s)
|
res = append(res, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
close(stop)
|
close(stop)
|
||||||
|
|
||||||
fmt.Println(res) //[* * * * *]
|
fmt.Println(res) //[* * * * *]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pipeline">Pipeline</span>
|
||||||
|
|
||||||
|
<p>管道执行多个函数</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{}
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
addOne := func(x interface{}) interface{} {
|
||||||
|
return x.(int) + 1
|
||||||
|
}
|
||||||
|
double := func(x interface{}) interface{} {
|
||||||
|
return 2 * x.(int)
|
||||||
|
}
|
||||||
|
square := func(x interface{}) interface{} {
|
||||||
|
return x.(int) * x.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := function.Pipeline(addOne, double, square)
|
||||||
|
|
||||||
|
result := fn(2)
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 36
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Watcher">Watcher</span>
|
### <span id="Watcher">Watcher</span>
|
||||||
|
|
||||||
@@ -311,15 +350,16 @@ func main() {
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
type Watcher struct {
|
type Watcher struct {
|
||||||
startTime int64
|
startTime int64
|
||||||
stopTime int64
|
stopTime int64
|
||||||
excuting bool
|
excuting bool
|
||||||
}
|
}
|
||||||
func (w *Watcher) Start() //start the watcher
|
func (w *Watcher) Start() //start the watcher
|
||||||
func (w *Watcher) Stop() //stop the watcher
|
func (w *Watcher) Stop() //stop the watcher
|
||||||
func (w *Watcher) Reset() //reset the watcher
|
func (w *Watcher) Reset() //reset the watcher
|
||||||
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -332,33 +372,30 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
w := &function.Watcher{}
|
w := &function.Watcher{}
|
||||||
w.Start()
|
w.Start()
|
||||||
|
|
||||||
longRunningTask()
|
longRunningTask()
|
||||||
|
|
||||||
fmt.Println(w.excuting) //true
|
fmt.Println(w.excuting) //true
|
||||||
|
|
||||||
w.Stop()
|
w.Stop()
|
||||||
|
|
||||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||||
fmt.Println(eapsedTime)
|
fmt.Println(eapsedTime)
|
||||||
|
|
||||||
w.Reset()
|
w.Reset()
|
||||||
|
|
||||||
fmt.Println(w.excuting) //false
|
fmt.Println(w.excuting) //false
|
||||||
|
|
||||||
fmt.Println(w.startTime) //0
|
fmt.Println(w.startTime) //0
|
||||||
fmt.Println(w.stopTime) //0
|
fmt.Println(w.stopTime) //0
|
||||||
}
|
}
|
||||||
|
|
||||||
func longRunningTask() {
|
func longRunningTask() {
|
||||||
var slice []int64
|
var slice []int64
|
||||||
for i := 0; i < 10000000; i++ {
|
for i := 0; i < 10000000; i++ {
|
||||||
slice = append(slice, int64(i))
|
slice = append(slice, int64(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
451
docs/mathutil.md
451
docs/mathutil.md
@@ -1,16 +1,17 @@
|
|||||||
# Mathutil
|
# Mathutil
|
||||||
|
|
||||||
Package mathutil implements some functions for math calculation.
|
Package mathutil implements some functions for math calculation.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
[https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Example:
|
## Example:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/mathutil"
|
"github.com/duke-git/lancet/mathutil"
|
||||||
@@ -20,20 +21,30 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [Exponent](#Exponent)
|
|
||||||
- [Fibonacci](#Fibonacci)
|
- [Exponent](#Exponent)
|
||||||
- [Factorial](#Factorial)
|
- [Fibonacci](#Fibonacci)
|
||||||
- [Percent](#Percent)
|
- [Factorial](#Factorial)
|
||||||
- [RoundToFloat](#RoundToFloat)
|
- [Percent](#Percent)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [TruncRound](#TruncRound)
|
- [RoundToString](#RoundToString)
|
||||||
|
- [TruncRound](#TruncRound)
|
||||||
|
- [AngleToRadian](#AngleToRadian)
|
||||||
|
- [RadianToAngle](#RadianToAngle)
|
||||||
|
- [PointDistance](#PointDistance)
|
||||||
|
- [IsPrime](#IsPrime)
|
||||||
|
- [GCD](#GCD)
|
||||||
|
- [LCM](#LCM)
|
||||||
|
- [Cos](#Cos)
|
||||||
|
- [Sin](#Sin)
|
||||||
|
- [Log](#Log)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
### <span id="Exponent">Exponent</span>
|
### <span id="Exponent">Exponent</span>
|
||||||
|
|
||||||
<p>Calculate x to the nth power.</p>
|
<p>Calculate x to the nth power.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -41,6 +52,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func Exponent(x, n int64) int64
|
func Exponent(x, n int64) int64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -52,15 +64,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Fibonacci">Fibonacci</span>
|
### <span id="Fibonacci">Fibonacci</span>
|
||||||
|
|
||||||
<p>Calculate the nth number of fibonacci sequence.</p>
|
<p>Calculate the nth number of fibonacci sequence.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -68,6 +79,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Fibonacci(first, second, n int) int
|
func Fibonacci(first, second, n int) int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -79,17 +91,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Factorial">Factorial</span>
|
### <span id="Factorial">Factorial</span>
|
||||||
|
|
||||||
<p>Calculate the factorial of x.</p>
|
<p>Calculate the factorial of x.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -97,6 +108,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Factorial(x uint) uint
|
func Factorial(x uint) uint
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -108,16 +120,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Factorial(0)) //1
|
fmt.Println(mathutil.Factorial(0)) //1
|
||||||
fmt.Println(mathutil.Factorial(1)) //1
|
fmt.Println(mathutil.Factorial(1)) //1
|
||||||
fmt.Println(mathutil.Factorial(2)) //2
|
fmt.Println(mathutil.Factorial(2)) //2
|
||||||
fmt.Println(mathutil.Factorial(3)) //6
|
fmt.Println(mathutil.Factorial(3)) //6
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Percent">Percent</span>
|
### <span id="Percent">Percent</span>
|
||||||
|
|
||||||
<p>calculate the percentage of val to total, retain n decimal places.</p>
|
<p>calculate the percentage of val to total, retain n decimal places.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -125,6 +136,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Percent(val, total float64, n int) float64
|
func Percent(val, total float64, n int) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -136,14 +148,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RoundToFloat">RoundToFloat</span>
|
### <span id="RoundToFloat">RoundToFloat</span>
|
||||||
|
|
||||||
<p>Round float up to n decimal places.</p>
|
<p>Round float up to n decimal places.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -151,6 +162,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RoundToFloat(x float64, n int) float64
|
func RoundToFloat(x float64, n int) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -162,18 +174,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RoundToString">RoundToString</span>
|
### <span id="RoundToString">RoundToString</span>
|
||||||
|
|
||||||
<p>Round float up to n decimal places. will return string.</p>
|
<p>Round float up to n decimal places. will return string.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -181,6 +191,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RoundToString(x float64, n int) string
|
func RoundToString(x float64, n int) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -192,17 +203,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="TruncRound">TruncRound</span>
|
### <span id="TruncRound">TruncRound</span>
|
||||||
|
|
||||||
<p>Round float off n decimal places.</p>
|
<p>Round float off n decimal places.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -210,6 +220,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func TruncRound(x float64, n int) float64
|
func TruncRound(x float64, n int) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -221,13 +232,349 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="AngleToRadian">AngleToRadian</span>
|
||||||
|
|
||||||
|
<p>Converts angle value to radian value.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AngleToRadian(angle float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.AngleToRadian(45)
|
||||||
|
result2 := mathutil.AngleToRadian(90)
|
||||||
|
result3 := mathutil.AngleToRadian(180)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0.7853981633974483
|
||||||
|
// 1.5707963267948966
|
||||||
|
// 3.141592653589793
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RadianToAngle">RadianToAngle</span>
|
||||||
|
|
||||||
|
<p>Converts radian value to angle value.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RadianToAngle(radian float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RadianToAngle(math.Pi)
|
||||||
|
result2 := mathutil.RadianToAngle(math.Pi / 2)
|
||||||
|
result3 := mathutil.RadianToAngle(math.Pi / 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 180
|
||||||
|
// 90
|
||||||
|
// 45
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="PointDistance">PointDistance</span>
|
||||||
|
|
||||||
|
<p>Caculates two points distance.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PointDistance(x1, y1, x2, y2 float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.PointDistance(1, 1, 4, 5)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsPrime">IsPrime</span>
|
||||||
|
|
||||||
|
<p>Checks if number is prime number.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsPrime(n int) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.IsPrime(-1)
|
||||||
|
result2 := mathutil.IsPrime(0)
|
||||||
|
result3 := mathutil.IsPrime(1)
|
||||||
|
result4 := mathutil.IsPrime(2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GCD">GCD</span>
|
||||||
|
|
||||||
|
<p>Return greatest common divisor (GCD) of integers.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GCD(integers ...int) int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.GCD(1, 1)
|
||||||
|
result2 := mathutil.GCD(1, -1)
|
||||||
|
result3 := mathutil.GCD(-1, 1)
|
||||||
|
result4 := mathutil.GCD(-1, -1)
|
||||||
|
result5 := mathutil.GCD(3, 6, 9)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// -1
|
||||||
|
// -1
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="LCM">LCM</span>
|
||||||
|
|
||||||
|
<p>Return Least Common Multiple (LCM) of integers.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func LCM(integers ...int) int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.LCM(1, 1)
|
||||||
|
result2 := mathutil.LCM(1, 2)
|
||||||
|
result3 := mathutil.LCM(3, 6, 9)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 2
|
||||||
|
// 18
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Cos">Cos</span>
|
||||||
|
|
||||||
|
<p>Returns the cosine of the radian argument.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Cos(radian float64, precision ...int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Cos(0)
|
||||||
|
result2 := mathutil.Cos(90)
|
||||||
|
result3 := mathutil.Cos(180)
|
||||||
|
result4 := mathutil.Cos(math.Pi)
|
||||||
|
result5 := mathutil.Cos(math.Pi / 2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// -0.447
|
||||||
|
// -0.598
|
||||||
|
// -1
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Sin">Sin</span>
|
||||||
|
|
||||||
|
<p>Returns the sine of the radian argument.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sin(radian float64, precision ...int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Sin(0)
|
||||||
|
result2 := mathutil.Sin(90)
|
||||||
|
result3 := mathutil.Sin(180)
|
||||||
|
result4 := mathutil.Sin(math.Pi)
|
||||||
|
result5 := mathutil.Sin(math.Pi / 2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
// 0.894
|
||||||
|
// -0.801
|
||||||
|
// 0
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Log">Log</span>
|
||||||
|
|
||||||
|
<p>Returns the logarithm of base n.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Log(n, base float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Log(8, 2)
|
||||||
|
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||||
|
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
// 2.32
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
# Mathutil
|
# Mathutil
|
||||||
mathutil包实现了一些数学计算的函数.
|
|
||||||
|
mathutil 包实现了一些数学计算的函数.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
[https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法:
|
## 用法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/mathutil"
|
"github.com/duke-git/lancet/mathutil"
|
||||||
@@ -20,21 +21,30 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
- [Exponent](#Exponent)
|
|
||||||
- [Fibonacci](#Fibonacci)
|
|
||||||
- [Factorial](#Factorial)
|
|
||||||
|
|
||||||
- [Percent](#Percent)
|
- [Exponent](#Exponent)
|
||||||
- [RoundToFloat](#RoundToFloat)
|
- [Fibonacci](#Fibonacci)
|
||||||
- [RoundToString](#RoundToString)
|
- [Factorial](#Factorial)
|
||||||
- [TruncRound](#TruncRound)
|
- [Percent](#Percent)
|
||||||
|
- [RoundToFloat](#RoundToFloat)
|
||||||
|
- [RoundToString](#RoundToString)
|
||||||
|
- [TruncRound](#TruncRound)
|
||||||
|
- [AngleToRadian](#AngleToRadian)
|
||||||
|
- [RadianToAngle](#RadianToAngle)
|
||||||
|
- [PointDistance](#PointDistance)
|
||||||
|
- [IsPrime](#IsPrime)
|
||||||
|
- [GCD](#GCD)
|
||||||
|
- [LCM](#LCM)
|
||||||
|
- [Cos](#Cos)
|
||||||
|
- [Sin](#Sin)
|
||||||
|
- [Log](#Log)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
### <span id="Exponent">Exponent</span>
|
### <span id="Exponent">Exponent</span>
|
||||||
|
|
||||||
<p>指数计算(x的n次方)</p>
|
<p>指数计算(x的n次方)</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -42,6 +52,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func Exponent(x, n int64) int64
|
func Exponent(x, n int64) int64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -53,15 +64,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Fibonacci">Fibonacci</span>
|
### <span id="Fibonacci">Fibonacci</span>
|
||||||
|
|
||||||
<p>计算斐波那契数列的第n个数</p>
|
<p>计算斐波那契数列的第n个数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -69,6 +79,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Fibonacci(first, second, n int) int
|
func Fibonacci(first, second, n int) int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -80,17 +91,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Factorial">Factorial</span>
|
### <span id="Factorial">Factorial</span>
|
||||||
|
|
||||||
<p>计算阶乘</p>
|
<p>计算阶乘</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -98,6 +108,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Factorial(x uint) uint
|
func Factorial(x uint) uint
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -109,16 +120,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Factorial(0)) //1
|
fmt.Println(mathutil.Factorial(0)) //1
|
||||||
fmt.Println(mathutil.Factorial(1)) //1
|
fmt.Println(mathutil.Factorial(1)) //1
|
||||||
fmt.Println(mathutil.Factorial(2)) //2
|
fmt.Println(mathutil.Factorial(2)) //2
|
||||||
fmt.Println(mathutil.Factorial(3)) //6
|
fmt.Println(mathutil.Factorial(3)) //6
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Percent">Percent</span>
|
### <span id="Percent">Percent</span>
|
||||||
|
|
||||||
<p>计算百分比,保留n位小数</p>
|
<p>计算百分比,保留n位小数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -126,6 +136,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Percent(val, total float64, n int) float64
|
func Percent(val, total float64, n int) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -137,14 +148,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RoundToFloat">RoundToFloat</span>
|
### <span id="RoundToFloat">RoundToFloat</span>
|
||||||
|
|
||||||
<p>四舍五入,保留n位小数</p>
|
<p>四舍五入,保留n位小数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -152,6 +162,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RoundToFloat(x float64, n int) float64
|
func RoundToFloat(x float64, n int) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -163,18 +174,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RoundToString">RoundToString</span>
|
### <span id="RoundToString">RoundToString</span>
|
||||||
|
|
||||||
<p>四舍五入,保留n位小数,返回字符串</p>
|
<p>四舍五入,保留n位小数,返回字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -182,6 +191,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RoundToString(x float64, n int) string
|
func RoundToString(x float64, n int) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -193,17 +203,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="TruncRound">TruncRound</span>
|
### <span id="TruncRound">TruncRound</span>
|
||||||
|
|
||||||
<p>截短n位小数(不进行四舍五入)</p>
|
<p>截短n位小数(不进行四舍五入)</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -211,6 +220,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func TruncRound(x float64, n int) float64
|
func TruncRound(x float64, n int) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -222,13 +232,352 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AngleToRadian">AngleToRadian</span>
|
||||||
|
|
||||||
|
<p>将角度值转为弧度值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AngleToRadian(angle float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.AngleToRadian(45)
|
||||||
|
result2 := mathutil.AngleToRadian(90)
|
||||||
|
result3 := mathutil.AngleToRadian(180)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0.7853981633974483
|
||||||
|
// 1.5707963267948966
|
||||||
|
// 3.141592653589793
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RadianToAngle">RadianToAngle</span>
|
||||||
|
|
||||||
|
<p>将弧度值转为角度值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RadianToAngle(radian float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RadianToAngle(math.Pi)
|
||||||
|
result2 := mathutil.RadianToAngle(math.Pi / 2)
|
||||||
|
result3 := mathutil.RadianToAngle(math.Pi / 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 180
|
||||||
|
// 90
|
||||||
|
// 45
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="PointDistance">PointDistance</span>
|
||||||
|
|
||||||
|
<p>计算两个坐标点的距离</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PointDistance(x1, y1, x2, y2 float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.PointDistance(1, 1, 4, 5)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsPrime">IsPrime</span>
|
||||||
|
|
||||||
|
<p>判断质数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsPrime(n int) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.IsPrime(-1)
|
||||||
|
result2 := mathutil.IsPrime(0)
|
||||||
|
result3 := mathutil.IsPrime(1)
|
||||||
|
result4 := mathutil.IsPrime(2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="GCD">GCD</span>
|
||||||
|
|
||||||
|
<p>计算整数最大公约数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GCD(integers ...int) int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.GCD(1, 1)
|
||||||
|
result2 := mathutil.GCD(1, -1)
|
||||||
|
result3 := mathutil.GCD(-1, 1)
|
||||||
|
result4 := mathutil.GCD(-1, -1)
|
||||||
|
result5 := mathutil.GCD(3, 6, 9)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// -1
|
||||||
|
// -1
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="LCM">LCM</span>
|
||||||
|
|
||||||
|
<p>计算整数最小公倍数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func LCM(integers ...int) int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.LCM(1, 1)
|
||||||
|
result2 := mathutil.LCM(1, 2)
|
||||||
|
result3 := mathutil.LCM(3, 6, 9)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 2
|
||||||
|
// 18
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="Cos">Cos</span>
|
||||||
|
|
||||||
|
<p>计算弧度的余弦值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Cos(radian float64, precision ...int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Cos(0)
|
||||||
|
result2 := mathutil.Cos(90)
|
||||||
|
result3 := mathutil.Cos(180)
|
||||||
|
result4 := mathutil.Cos(math.Pi)
|
||||||
|
result5 := mathutil.Cos(math.Pi / 2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// -0.447
|
||||||
|
// -0.598
|
||||||
|
// -1
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="Sin">Sin</span>
|
||||||
|
|
||||||
|
<p>计算弧度的正弦值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sin(radian float64, precision ...int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Sin(0)
|
||||||
|
result2 := mathutil.Sin(90)
|
||||||
|
result3 := mathutil.Sin(180)
|
||||||
|
result4 := mathutil.Sin(math.Pi)
|
||||||
|
result5 := mathutil.Sin(math.Pi / 2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
// 0.894
|
||||||
|
// -0.801
|
||||||
|
// 0
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Log">Log</span>
|
||||||
|
|
||||||
|
<p>计算以base为底n的对数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Log(n, base float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Log(8, 2)
|
||||||
|
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||||
|
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
// 2.32
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
838
docs/netutil.md
838
docs/netutil.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
174
docs/random.md
174
docs/random.md
@@ -1,16 +1,17 @@
|
|||||||
# Random
|
# Random
|
||||||
|
|
||||||
Package random implements some basic functions to generate random int and string.
|
Package random implements some basic functions to generate random int and string.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
|
[https://github.com/duke-git/lancet/blob/v1/random/random.go](https://github.com/duke-git/lancet/blob/v1/random/random.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/random"
|
"github.com/duke-git/lancet/random"
|
||||||
@@ -20,17 +21,23 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [RandBytes](#RandBytes)
|
|
||||||
- [RandInt](#RandInt)
|
- [RandBytes](#RandBytes)
|
||||||
- [RandString](#RandString)
|
- [RandInt](#RandInt)
|
||||||
- [UUIdV4](#UUIdV4)
|
- [RandString](#RandString)
|
||||||
|
- [RandUpper](#RandUpper)
|
||||||
|
- [RandLower](#RandLower)
|
||||||
|
- [RandNumeral](#RandNumeral)
|
||||||
|
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||||
|
- [UUIdV4](#UUIdV4)
|
||||||
|
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
### <span id="RandBytes">RandBytes</span>
|
### <span id="RandBytes">RandBytes</span>
|
||||||
|
|
||||||
<p>Generate random byte slice.</p>
|
<p>Generate random byte slice.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -38,6 +45,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func RandBytes(length int) []byte
|
func RandBytes(length int) []byte
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -49,13 +57,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
randBytes := random.RandBytes(4)
|
randBytes := random.RandBytes(4)
|
||||||
fmt.Println(randBytes)
|
fmt.Println(randBytes)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="RandInt">RandInt</span>
|
### <span id="RandInt">RandInt</span>
|
||||||
|
|
||||||
<p>Generate random int between min and max, may contain min, not max.</p>
|
<p>Generate random int between min and max, may contain min, not max.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -63,6 +71,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RandInt(min, max int) int
|
func RandInt(min, max int) int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -74,21 +83,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
rInt := random.RandInt(1, 10)
|
rInt := random.RandInt(1, 10)
|
||||||
fmt.Println(rInt)
|
fmt.Println(rInt)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="RandString">RandString</span>
|
||||||
|
|
||||||
|
<p>Generate random given length string. only contains letter (a-zA-Z)</p>
|
||||||
### <span id="RandString">RandInt</span>
|
|
||||||
<p>Generate random given length string.</p>
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func RandString(length int) string
|
func RandString(length int) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -100,15 +109,117 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
randStr := random.RandString(6)
|
randStr := random.RandString(6)
|
||||||
fmt.Println(randStr)
|
fmt.Println(randStr) //pGWsze
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="RandUpper">RandUpper</span>
|
||||||
|
|
||||||
|
<p>Generate a random upper case string</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandUpper(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandString(6)
|
||||||
|
fmt.Println(randStr) //PACWGF
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RandLower">RandLower</span>
|
||||||
|
|
||||||
|
<p>Generate a random lower case string</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandLower(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandLower(6)
|
||||||
|
fmt.Println(randStr) //siqbew
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RandNumeral">RandNumeral</span>
|
||||||
|
|
||||||
|
<p>Generate a random numeral string</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandNumeral(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandNumeral(6)
|
||||||
|
fmt.Println(randStr) //035172
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
|
||||||
|
|
||||||
|
<p>generate a random numeral or letter string</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandNumeralOrLetter(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandNumeralOrLetter(6)
|
||||||
|
fmt.Println(randStr) //0aW7cQ
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="UUIdV4">UUIdV4</span>
|
### <span id="UUIdV4">UUIdV4</span>
|
||||||
|
|
||||||
<p>Generate a random UUID of version 4 according to RFC 4122.</p>
|
<p>Generate a random UUID of version 4 according to RFC 4122.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -116,6 +227,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func UUIdV4() (string, error)
|
func UUIdV4() (string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -127,12 +239,36 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
uuid, err := random.UUIdV4()
|
uuid, err := random.UUIdV4()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(uuid)
|
fmt.Println(uuid)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
|
||||||
|
|
||||||
|
<p>Generate a slice of random int of length n that do not repeat.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandUniqueIntSlice(n, min, max int) []int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := RandUniqueIntSlice(5, 0, 10)
|
||||||
|
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
# Random
|
# Random
|
||||||
random随机数生成器包,可以生成随机[]bytes, int, string。
|
|
||||||
|
random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
|
[https://github.com/duke-git/lancet/blob/v1/random/random.go](https://github.com/duke-git/lancet/blob/v1/random/random.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法:
|
## 用法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/random"
|
"github.com/duke-git/lancet/random"
|
||||||
@@ -20,18 +21,23 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
- [RandBytes](#RandBytes)
|
|
||||||
- [RandInt](#RandInt)
|
|
||||||
- [RandString](#RandString)
|
|
||||||
- [UUIdV4](#UUIdV4)
|
|
||||||
|
|
||||||
|
- [RandBytes](#RandBytes)
|
||||||
|
- [RandInt](#RandInt)
|
||||||
|
- [RandString](#RandString)
|
||||||
|
- [RandUpper](#RandUpper)
|
||||||
|
- [RandLower](#RandLower)
|
||||||
|
- [RandNumeral](#RandNumeral)
|
||||||
|
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||||
|
- [UUIdV4](#UUIdV4)
|
||||||
|
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
|
||||||
### <span id="RandBytes">RandBytes</span>
|
### <span id="RandBytes">RandBytes</span>
|
||||||
|
|
||||||
<p>生成随机字节切片</p>
|
<p>生成随机字节切片</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -39,6 +45,7 @@ import (
|
|||||||
```go
|
```go
|
||||||
func RandBytes(length int) []byte
|
func RandBytes(length int) []byte
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -50,13 +57,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
randBytes := random.RandBytes(4)
|
randBytes := random.RandBytes(4)
|
||||||
fmt.Println(randBytes)
|
fmt.Println(randBytes)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="RandInt">RandInt</span>
|
### <span id="RandInt">RandInt</span>
|
||||||
|
|
||||||
<p>生成随机int, 范围[min, max)</p>
|
<p>生成随机int, 范围[min, max)</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -64,6 +71,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RandInt(min, max int) int
|
func RandInt(min, max int) int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -75,21 +83,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
rInt := random.RandInt(1, 10)
|
rInt := random.RandInt(1, 10)
|
||||||
fmt.Println(rInt)
|
fmt.Println(rInt)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="RandString">RandString</span>
|
||||||
|
|
||||||
|
<p>生成给定长度的随机字符串,只包含字母(a-zA-Z)</p>
|
||||||
### <span id="RandString">RandInt</span>
|
|
||||||
<p>生成随机给定长度的随机字符串</p>
|
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func RandString(length int) string
|
func RandString(length int) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -101,14 +109,117 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
randStr := random.RandString(6)
|
randStr := random.RandString(6)
|
||||||
fmt.Println(randStr)
|
fmt.Println(randStr) //pGWsze
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="RandUpper">RandUpper</span>
|
||||||
|
|
||||||
|
<p>生成给定长度的随机大写字母字符串</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandUpper(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandString(6)
|
||||||
|
fmt.Println(randStr) //PACWGF
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RandLower">RandLower</span>
|
||||||
|
|
||||||
|
<p>生成给定长度的随机小写字母字符串</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandLower(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandLower(6)
|
||||||
|
fmt.Println(randStr) //siqbew
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RandNumeral">RandNumeral</span>
|
||||||
|
|
||||||
|
<p>生成给定长度的随机数字字符串</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandNumeral(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandNumeral(6)
|
||||||
|
fmt.Println(randStr) //035172
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
|
||||||
|
|
||||||
|
<p>生成给定长度的随机字符串(数字+字母)</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandNumeralOrLetter(length int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
randStr := random.RandNumeralOrLetter(6)
|
||||||
|
fmt.Println(randStr) //0aW7cQ
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="UUIdV4">UUIdV4</span>
|
### <span id="UUIdV4">UUIdV4</span>
|
||||||
|
|
||||||
<p>生成UUID v4字符串</p>
|
<p>生成UUID v4字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -116,6 +227,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func UUIdV4() (string, error)
|
func UUIdV4() (string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -127,12 +239,36 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
uuid, err := random.UUIdV4()
|
uuid, err := random.UUIdV4()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(uuid)
|
fmt.Println(uuid)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
|
||||||
|
|
||||||
|
<p>生成一个不重复的长度为n的随机int切片。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RandUniqueIntSlice(n, min, max int) []int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := RandUniqueIntSlice(5, 0, 10)
|
||||||
|
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
157
docs/retry.md
157
docs/retry.md
@@ -1,16 +1,17 @@
|
|||||||
# Retry
|
# Retry
|
||||||
|
|
||||||
Package retry is for executing a function repeatedly until it was successful or canceled by the context.
|
Package retry is for executing a function repeatedly until it was successful or canceled by the context.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
|
[https://github.com/duke-git/lancet/blob/v1/retry/retry.go](https://github.com/duke-git/lancet/blob/v1/retry/retry.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/retry"
|
"github.com/duke-git/lancet/retry"
|
||||||
@@ -20,18 +21,19 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [Context](#Context)
|
|
||||||
- [Retry](#Retry)
|
- [Context](#Context)
|
||||||
- [RetryFunc](#RetryFunc)
|
- [Retry](#Retry)
|
||||||
- [RetryDuration](#RetryDuration)
|
- [RetryFunc](#RetryFunc)
|
||||||
- [RetryTimes](#RetryTimes)
|
- [RetryDuration](#RetryDuration)
|
||||||
|
- [RetryTimes](#RetryTimes)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
### <span id="Context">Context</span>
|
### <span id="Context">Context</span>
|
||||||
|
|
||||||
<p>Set retry context config, can cancel the retry with context.</p>
|
<p>Set retry context config, can cancel the retry with context.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -39,43 +41,42 @@ import (
|
|||||||
```go
|
```go
|
||||||
func Context(ctx context.Context)
|
func Context(ctx context.Context)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/retry"
|
"github.com/duke-git/lancet/retry"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := context.WithCancel(context.TODO())
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number > 3 {
|
if number > 3 {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber,
|
err := retry.Retry(increaseNumber,
|
||||||
retry.RetryDuration(time.Microsecond*50),
|
retry.RetryDuration(time.Microsecond*50),
|
||||||
retry.Context(ctx),
|
retry.Context(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err) //retry is cancelled
|
fmt.Println(err) //retry is cancelled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RetryFunc">RetryFunc</span>
|
### <span id="RetryFunc">RetryFunc</span>
|
||||||
|
|
||||||
<p>Function that retry executes.</p>
|
<p>Function that retry executes.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -83,6 +84,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
type RetryFunc func() error
|
type RetryFunc func() error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -98,26 +100,25 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
var increaseNumber retry.RetryFunc
|
var increaseNumber retry.RetryFunc
|
||||||
increaseNumber = func() error {
|
increaseNumber = func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(number) //3
|
fmt.Println(number) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RetryTimes">RetryTimes</span>
|
### <span id="RetryTimes">RetryTimes</span>
|
||||||
|
|
||||||
<p>Set times of retry. Default times is 5.</p>
|
<p>Set times of retry. Default times is 5.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -125,6 +126,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RetryTimes(n uint)
|
func RetryTimes(n uint)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -139,24 +141,23 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RetryDuration">RetryDuration</span>
|
### <span id="RetryDuration">RetryDuration</span>
|
||||||
|
|
||||||
<p>Set duration of retries. Default duration is 3 second.</p>
|
<p>Set duration of retries. Default duration is 3 second.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -164,6 +165,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RetryDuration(d time.Duration)
|
func RetryDuration(d time.Duration)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -178,25 +180,25 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(number) //3
|
fmt.Println(number) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="Retry">Retry</span>
|
### <span id="Retry">Retry</span>
|
||||||
|
|
||||||
<p>Executes the retryFunc repeatedly until it was successful or canceled by the context.</p>
|
<p>Executes the retryFunc repeatedly until it was successful or canceled by the context.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -204,6 +206,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Retry(retryFunc RetryFunc, opts ...Option) error
|
func Retry(retryFunc RetryFunc, opts ...Option) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -218,18 +221,18 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(number) //3
|
fmt.Println(number) //3
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
# Retry
|
# Retry
|
||||||
retry重试执行函数直到函数运行成功或被context cancel。
|
|
||||||
|
retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
|
[https://github.com/duke-git/lancet/blob/v1/retry/retry.go](https://github.com/duke-git/lancet/blob/v1/retry/retry.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法:
|
## 用法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/retry"
|
"github.com/duke-git/lancet/retry"
|
||||||
@@ -20,20 +21,19 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
- [Context](#Context)
|
|
||||||
- [Retry](#Retry)
|
|
||||||
- [RetryFunc](#RetryFunc)
|
|
||||||
- [RetryDuration](#RetryDuration)
|
|
||||||
- [RetryTimes](#RetryTimes)
|
|
||||||
|
|
||||||
|
- [Context](#Context)
|
||||||
|
- [Retry](#Retry)
|
||||||
|
- [RetryFunc](#RetryFunc)
|
||||||
|
- [RetryDuration](#RetryDuration)
|
||||||
|
- [RetryTimes](#RetryTimes)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Document 文档
|
||||||
## Document文档
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Context">Context</span>
|
### <span id="Context">Context</span>
|
||||||
|
|
||||||
<p>设置重试context参数</p>
|
<p>设置重试context参数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -41,43 +41,42 @@ import (
|
|||||||
```go
|
```go
|
||||||
func Context(ctx context.Context)
|
func Context(ctx context.Context)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"lancet-demo/retry"
|
"lancet-demo/retry"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := context.WithCancel(context.TODO())
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number > 3 {
|
if number > 3 {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber,
|
err := retry.Retry(increaseNumber,
|
||||||
retry.RetryDuration(time.Microsecond*50),
|
retry.RetryDuration(time.Microsecond*50),
|
||||||
retry.Context(ctx),
|
retry.Context(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err) //retry is cancelled
|
fmt.Println(err) //retry is cancelled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RetryFunc">RetryFunc</span>
|
### <span id="RetryFunc">RetryFunc</span>
|
||||||
|
|
||||||
<p>被重试执行的函数</p>
|
<p>被重试执行的函数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -85,6 +84,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
type RetryFunc func() error
|
type RetryFunc func() error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -100,26 +100,25 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
var increaseNumber retry.RetryFunc
|
var increaseNumber retry.RetryFunc
|
||||||
increaseNumber = func() error {
|
increaseNumber = func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(number) //3
|
fmt.Println(number) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RetryTimes">RetryTimes</span>
|
### <span id="RetryTimes">RetryTimes</span>
|
||||||
|
|
||||||
<p>设置重试次数,默认5</p>
|
<p>设置重试次数,默认5</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -127,6 +126,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RetryTimes(n uint)
|
func RetryTimes(n uint)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -141,24 +141,23 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RetryDuration">RetryDuration</span>
|
### <span id="RetryDuration">RetryDuration</span>
|
||||||
|
|
||||||
<p>设置重试间隔时间,默认3秒</p>
|
<p>设置重试间隔时间,默认3秒</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -166,6 +165,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RetryDuration(d time.Duration)
|
func RetryDuration(d time.Duration)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -180,25 +180,25 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(number) //3
|
fmt.Println(number) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="Retry">Retry</span>
|
### <span id="Retry">Retry</span>
|
||||||
|
|
||||||
<p>重试执行函数retryFunc,直到函数运行成功,或被context停止</p>
|
<p>重试执行函数retryFunc,直到函数运行成功,或被context停止</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -206,6 +206,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func Retry(retryFunc RetryFunc, opts ...Option) error
|
func Retry(retryFunc RetryFunc, opts ...Option) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -220,18 +221,18 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var number int
|
var number int
|
||||||
increaseNumber := func() error {
|
increaseNumber := func() error {
|
||||||
number++
|
number++
|
||||||
if number == 3 {
|
if number == 3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("error occurs")
|
return errors.New("error occurs")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(number) //3
|
fmt.Println(number) //3
|
||||||
}
|
}
|
||||||
|
|||||||
896
docs/slice.md
896
docs/slice.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1118
docs/strutil.md
1118
docs/strutil.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
155
docs/system.md
155
docs/system.md
@@ -1,16 +1,17 @@
|
|||||||
# System
|
# System
|
||||||
|
|
||||||
Package system contains some functions about os, runtime, shell command.
|
Package system contains some functions about os, runtime, shell command.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
|
[https://github.com/duke-git/lancet/blob/v1/system/os.go](https://github.com/duke-git/lancet/blob/v1/system/os.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
@@ -20,22 +21,23 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [IsWindows](#IsWindows)
|
|
||||||
- [IsLinux](#IsLinux)
|
- [IsWindows](#IsWindows)
|
||||||
- [IsMac](#IsMac)
|
- [IsLinux](#IsLinux)
|
||||||
- [GetOsEnv](#GetOsEnv)
|
- [IsMac](#IsMac)
|
||||||
- [SetOsEnv](#SetOsEnv)
|
- [GetOsEnv](#GetOsEnv)
|
||||||
- [RemoveOsEnv](#RemoveOsEnv)
|
- [SetOsEnv](#SetOsEnv)
|
||||||
- [CompareOsEnv](#CompareOsEnv)
|
- [RemoveOsEnv](#RemoveOsEnv)
|
||||||
- [ExecCommand](#ExecCommand)
|
- [CompareOsEnv](#CompareOsEnv)
|
||||||
|
- [ExecCommand](#ExecCommand)
|
||||||
|
- [GetOsBits](#GetOsBits)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsWindows">IsWindows</span>
|
### <span id="IsWindows">IsWindows</span>
|
||||||
|
|
||||||
<p>Check if current os is windows.</p>
|
<p>Check if current os is windows.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -43,24 +45,23 @@ import (
|
|||||||
```go
|
```go
|
||||||
func IsWindows() bool
|
func IsWindows() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsWindows := system.IsWindows()
|
isOsWindows := system.IsWindows()
|
||||||
fmt.Println(isOsWindows)
|
fmt.Println(isOsWindows)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsLinux">IsLinux</span>
|
### <span id="IsLinux">IsLinux</span>
|
||||||
|
|
||||||
<p>Check if current os is linux.</p>
|
<p>Check if current os is linux.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -68,23 +69,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsLinux() bool
|
func IsLinux() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsLinux := system.IsLinux()
|
isOsLinux := system.IsLinux()
|
||||||
fmt.Println(isOsLinux)
|
fmt.Println(isOsLinux)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsMac">IsMac</span>
|
### <span id="IsMac">IsMac</span>
|
||||||
|
|
||||||
<p>Check if current os is macos.</p>
|
<p>Check if current os is macos.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -92,23 +93,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsMac() bool
|
func IsMac() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsMac := system.IsMac
|
isOsMac := system.IsMac
|
||||||
fmt.Println(isOsMac)
|
fmt.Println(isOsMac)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="GetOsEnv">GetOsEnv</span>
|
### <span id="GetOsEnv">GetOsEnv</span>
|
||||||
|
|
||||||
<p>Gets the value of the environment variable named by the key.</p>
|
<p>Gets the value of the environment variable named by the key.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -116,23 +117,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func GetOsEnv(key string) string
|
func GetOsEnv(key string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fooEnv := system.GetOsEnv("foo")
|
fooEnv := system.GetOsEnv("foo")
|
||||||
fmt.Println(fooEnv)
|
fmt.Println(fooEnv)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="SetOsEnv">SetOsEnv</span>
|
### <span id="SetOsEnv">SetOsEnv</span>
|
||||||
|
|
||||||
<p>Sets the value of the environment variable named by the key.</p>
|
<p>Sets the value of the environment variable named by the key.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -140,24 +141,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func SetOsEnv(key, value string) error
|
func SetOsEnv(key, value string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := system.SetOsEnv("foo", "foo_value")
|
err := system.SetOsEnv("foo", "foo_value")
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
||||||
|
|
||||||
<p>Remove a single environment variable.</p>
|
<p>Remove a single environment variable.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -165,25 +165,25 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RemoveOsEnv(key string) error
|
func RemoveOsEnv(key string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := system.RemoveOsEnv("foo")
|
err := system.RemoveOsEnv("foo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="CompareOsEnv">CompareOsEnv</span>
|
### <span id="CompareOsEnv">CompareOsEnv</span>
|
||||||
|
|
||||||
<p>Get env named by the key and compare it with comparedEnv.</p>
|
<p>Get env named by the key and compare it with comparedEnv.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -191,52 +191,71 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func CompareOsEnv(key, comparedEnv string) bool
|
func CompareOsEnv(key, comparedEnv string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
system.SetOsEnv("foo", "foo_value")
|
system.SetOsEnv("foo", "foo_value")
|
||||||
res := system.CompareOsEnv("foo", "foo_value")
|
res := system.CompareOsEnv("foo", "foo_value")
|
||||||
fmt.Println(res) //true
|
fmt.Println(res) //true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ExecCommand">ExecCommand</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ExecCommand">CompareOsEnv</span>
|
|
||||||
<p>use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
|
<p>use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func ExecCommand(command string) (stdout, stderr string, err error)
|
type (
|
||||||
|
Option func(*exec.Cmd)
|
||||||
|
)
|
||||||
|
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out, errout, err := system.ExecCommand("ls")
|
out, errout, err := system.ExecCommand("ls", system.WithForeground())
|
||||||
fmt.Println(out)
|
fmt.Println(out)
|
||||||
fmt.Println(errout)
|
fmt.Println(errout)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="GetOsBits">GetOsBits</span>
|
||||||
|
|
||||||
|
<p>获取当前操作系统位数,返回32或64</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetOsBits() int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
osBit := system.GetOsBits()
|
||||||
|
fmt.Println(osBit)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
# System
|
# System
|
||||||
system包含os, runtime, shell command相关函数。
|
|
||||||
|
system 包含 os, runtime, shell command 相关函数。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
[https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
|
[https://github.com/duke-git/lancet/blob/v1/system/os.go](https://github.com/duke-git/lancet/blob/v1/system/os.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法:
|
## 用法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
@@ -20,22 +21,23 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
- [IsWindows](#IsWindows)
|
|
||||||
- [IsLinux](#IsLinux)
|
- [IsWindows](#IsWindows)
|
||||||
- [IsMac](#IsMac)
|
- [IsLinux](#IsLinux)
|
||||||
- [GetOsEnv](#GetOsEnv)
|
- [IsMac](#IsMac)
|
||||||
- [SetOsEnv](#SetOsEnv)
|
- [GetOsEnv](#GetOsEnv)
|
||||||
- [RemoveOsEnv](#RemoveOsEnv)
|
- [SetOsEnv](#SetOsEnv)
|
||||||
- [CompareOsEnv](#CompareOsEnv)
|
- [RemoveOsEnv](#RemoveOsEnv)
|
||||||
- [ExecCommand](#ExecCommand)
|
- [CompareOsEnv](#CompareOsEnv)
|
||||||
|
- [ExecCommand](#ExecCommand)
|
||||||
|
- [GetOsBits](#GetOsBits)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation文档
|
## Documentation 文档
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsWindows">IsWindows</span>
|
### <span id="IsWindows">IsWindows</span>
|
||||||
|
|
||||||
<p>检查当前操作系统是否是windows</p>
|
<p>检查当前操作系统是否是windows</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -43,24 +45,23 @@ import (
|
|||||||
```go
|
```go
|
||||||
func IsWindows() bool
|
func IsWindows() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsWindows := system.IsWindows()
|
isOsWindows := system.IsWindows()
|
||||||
fmt.Println(isOsWindows)
|
fmt.Println(isOsWindows)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsLinux">IsLinux</span>
|
### <span id="IsLinux">IsLinux</span>
|
||||||
|
|
||||||
<p>检查当前操作系统是否是linux</p>
|
<p>检查当前操作系统是否是linux</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -68,23 +69,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsLinux() bool
|
func IsLinux() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsLinux := system.IsLinux()
|
isOsLinux := system.IsLinux()
|
||||||
fmt.Println(isOsLinux)
|
fmt.Println(isOsLinux)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsMac">IsMac</span>
|
### <span id="IsMac">IsMac</span>
|
||||||
|
|
||||||
<p>检查当前操作系统是否是macos</p>
|
<p>检查当前操作系统是否是macos</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -92,23 +93,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func IsMac() bool
|
func IsMac() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsMac := system.IsMac
|
isOsMac := system.IsMac
|
||||||
fmt.Println(isOsMac)
|
fmt.Println(isOsMac)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="GetOsEnv">GetOsEnv</span>
|
### <span id="GetOsEnv">GetOsEnv</span>
|
||||||
|
|
||||||
<p>获取key命名的环境变量的值</p>
|
<p>获取key命名的环境变量的值</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -116,23 +117,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func GetOsEnv(key string) string
|
func GetOsEnv(key string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fooEnv := system.GetOsEnv("foo")
|
fooEnv := system.GetOsEnv("foo")
|
||||||
fmt.Println(fooEnv)
|
fmt.Println(fooEnv)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="SetOsEnv">SetOsEnv</span>
|
### <span id="SetOsEnv">SetOsEnv</span>
|
||||||
|
|
||||||
<p>设置由key命名的环境变量的值</p>
|
<p>设置由key命名的环境变量的值</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -140,24 +141,23 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func SetOsEnv(key, value string) error
|
func SetOsEnv(key, value string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := system.SetOsEnv("foo", "foo_value")
|
err := system.SetOsEnv("foo", "foo_value")
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
||||||
|
|
||||||
<p>删除单个环境变量</p>
|
<p>删除单个环境变量</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -165,25 +165,25 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func RemoveOsEnv(key string) error
|
func RemoveOsEnv(key string) error
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := system.RemoveOsEnv("foo")
|
err := system.RemoveOsEnv("foo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="CompareOsEnv">CompareOsEnv</span>
|
### <span id="CompareOsEnv">CompareOsEnv</span>
|
||||||
|
|
||||||
<p>获取key命名的环境变量值并与compareEnv进行比较</p>
|
<p>获取key命名的环境变量值并与compareEnv进行比较</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -191,52 +191,71 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func CompareOsEnv(key, comparedEnv string) bool
|
func CompareOsEnv(key, comparedEnv string) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
system.SetOsEnv("foo", "foo_value")
|
system.SetOsEnv("foo", "foo_value")
|
||||||
res := system.CompareOsEnv("foo", "foo_value")
|
res := system.CompareOsEnv("foo", "foo_value")
|
||||||
fmt.Println(res) //true
|
fmt.Println(res) //true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ExecCommand">ExecCommand</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ExecCommand">CompareOsEnv</span>
|
|
||||||
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func ExecCommand(command string) (stdout, stderr string, err error)
|
type (
|
||||||
|
Option func(*exec.Cmd)
|
||||||
|
)
|
||||||
|
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/system"
|
"github.com/duke-git/lancet/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out, errout, err := system.ExecCommand("ls")
|
out, errout, err := system.ExecCommand("ls", system.WithForeground())
|
||||||
fmt.Println(out)
|
fmt.Println(out)
|
||||||
fmt.Println(errout)
|
fmt.Println(errout)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="GetOsBits">GetOsBits</span>
|
||||||
|
|
||||||
|
<p>Get current os bits, 32bit or 64bit. return 32 or 64</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetOsBits() int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
osBit := system.GetOsBits()
|
||||||
|
fmt.Println(osBit)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
1132
docs/validator.md
1132
docs/validator.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
344
fileutil/file.go
344
fileutil/file.go
@@ -7,14 +7,23 @@ package fileutil
|
|||||||
import (
|
import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
|
"encoding/csv"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsExist checks if a file or directory exists
|
// IsExist checks if a file or directory exists
|
||||||
@@ -40,6 +49,11 @@ func CreateFile(path string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
|
||||||
|
func CreateDir(absPath string) error {
|
||||||
|
return os.MkdirAll(absPath, os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
// IsDir checks if the path is directory or not
|
// IsDir checks if the path is directory or not
|
||||||
func IsDir(path string) bool {
|
func IsDir(path string) bool {
|
||||||
file, err := os.Stat(path)
|
file, err := os.Stat(path)
|
||||||
@@ -81,7 +95,7 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ClearFile write empty string to path file
|
// ClearFile write empty string to path file
|
||||||
func ClearFile(path string) error {
|
func ClearFile(path string) error {
|
||||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -93,7 +107,7 @@ func ClearFile(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -155,7 +169,15 @@ func ListFileNames(path string) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Zip create zip file, fpath could be a single file or a directory
|
// Zip create zip file, fpath could be a single file or a directory
|
||||||
func Zip(fpath string, destPath string) error {
|
func Zip(path string, destPath string) error {
|
||||||
|
if IsDir(path) {
|
||||||
|
return zipFolder(path, destPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return zipFile(path, destPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func zipFile(filePath string, destPath string) error {
|
||||||
zipFile, err := os.Create(destPath)
|
zipFile, err := os.Create(destPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -165,7 +187,33 @@ 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 {
|
return addFileToArchive1(filePath, archive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func zipFolder(folderPath string, destPath string) error {
|
||||||
|
outFile, err := os.Create(destPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
w := zip.NewWriter(outFile)
|
||||||
|
|
||||||
|
err = addFileToArchive2(w, folderPath, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFileToArchive1(fpath string, archive *zip.Writer) error {
|
||||||
|
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -181,26 +229,53 @@ func Zip(fpath string, destPath string) error {
|
|||||||
header.Name += "/"
|
header.Name += "/"
|
||||||
} else {
|
} else {
|
||||||
header.Method = zip.Deflate
|
header.Method = zip.Deflate
|
||||||
}
|
writer, err := archive.CreateHeader(header)
|
||||||
|
if err != nil {
|
||||||
writer, err := archive.CreateHeader(header)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !info.IsDir() {
|
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
_, err = io.Copy(writer, file)
|
if _, err := io.Copy(writer, file); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFileToArchive2(w *zip.Writer, basePath, baseInZip string) error {
|
||||||
|
files, err := os.ReadDir(basePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(basePath, "/") {
|
||||||
|
basePath = basePath + "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if !file.IsDir() {
|
||||||
|
dat, err := os.ReadFile(basePath + file.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := w.Create(baseInZip + file.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = f.Write(dat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if file.IsDir() {
|
||||||
|
newBase := basePath + file.Name() + "/"
|
||||||
|
addFileToArchive2(w, newBase, baseInZip+file.Name()+"/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -214,7 +289,11 @@ func UnZip(zipFile string, destPath string) error {
|
|||||||
defer zipReader.Close()
|
defer zipReader.Close()
|
||||||
|
|
||||||
for _, f := range zipReader.File {
|
for _, f := range zipReader.File {
|
||||||
path := filepath.Join(destPath, f.Name)
|
//issue#62: fix ZipSlip bug
|
||||||
|
path, err := safeFilepathJoin(destPath, f.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if f.FileInfo().IsDir() {
|
if f.FileInfo().IsDir() {
|
||||||
os.MkdirAll(path, os.ModePerm)
|
os.MkdirAll(path, os.ModePerm)
|
||||||
} else {
|
} else {
|
||||||
@@ -243,6 +322,75 @@ func UnZip(zipFile string, destPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ZipAppendEntry append a single file or directory by fpath to an existing zip file.
|
||||||
|
// Play: https://go.dev/play/p/cxvaT8TRNQp
|
||||||
|
func ZipAppendEntry(fpath string, destPath string) error {
|
||||||
|
tempFile, err := os.CreateTemp("", "temp.zip")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.Remove(tempFile.Name())
|
||||||
|
|
||||||
|
zipReader, err := zip.OpenReader(destPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
archive := zip.NewWriter(tempFile)
|
||||||
|
|
||||||
|
for _, zipItem := range zipReader.File {
|
||||||
|
zipItemReader, err := zipItem.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
header, err := zip.FileInfoHeader(zipItem.FileInfo())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
header.Name = zipItem.Name
|
||||||
|
targetItem, err := archive.CreateHeader(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(targetItem, zipItemReader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = addFileToArchive1(fpath, archive)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zipReader.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = archive.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tempFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return CopyFile(tempFile.Name(), destPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||||
|
relPath, err := filepath.Rel(".", path2)
|
||||||
|
if err != nil || strings.HasPrefix(relPath, "..") {
|
||||||
|
return "", fmt.Errorf("(zipslip) filepath is unsafe %q: %v", path2, err)
|
||||||
|
}
|
||||||
|
if path1 == "" {
|
||||||
|
path1 = "."
|
||||||
|
}
|
||||||
|
return filepath.Join(path1, filepath.Join("/", relPath)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsLink checks if a file is symbol link or not
|
// IsLink checks if a file is symbol link or not
|
||||||
func IsLink(path string) bool {
|
func IsLink(path string) bool {
|
||||||
fi, err := os.Lstat(path)
|
fi, err := os.Lstat(path)
|
||||||
@@ -296,3 +444,169 @@ func MiMeType(file interface{}) string {
|
|||||||
}
|
}
|
||||||
return mediatype
|
return mediatype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CurrentPath return current absolute path.
|
||||||
|
func CurrentPath() string {
|
||||||
|
var absPath string
|
||||||
|
_, filename, _, ok := runtime.Caller(1)
|
||||||
|
if ok {
|
||||||
|
absPath = filepath.Dir(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
return absPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZipFile checks if file is zip or not.
|
||||||
|
func IsZipFile(filepath string) bool {
|
||||||
|
f, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
buf := make([]byte, 4)
|
||||||
|
if n, err := f.Read(buf); err != nil || n < 4 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.Equal(buf, []byte("PK\x03\x04"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileSize returns file size in bytes.
|
||||||
|
func FileSize(path string) (int64, error) {
|
||||||
|
f, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return f.Size(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MTime returns file modified time.
|
||||||
|
func MTime(filepath string) (int64, error) {
|
||||||
|
f, err := os.Stat(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return f.ModTime().Unix(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha returns file sha value, param `shaType` should be 1, 256 or 512.
|
||||||
|
func Sha(filepath string, shaType ...int) (string, error) {
|
||||||
|
file, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
if len(shaType) > 0 {
|
||||||
|
if shaType[0] == 1 {
|
||||||
|
h = sha1.New()
|
||||||
|
} else if shaType[0] == 256 {
|
||||||
|
h = sha256.New()
|
||||||
|
} else if shaType[0] == 512 {
|
||||||
|
h = sha512.New()
|
||||||
|
} else {
|
||||||
|
return "", errors.New("param `shaType` should be 1, 256 or 512.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(h, file)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sha := fmt.Sprintf("%x", h.Sum(nil))
|
||||||
|
|
||||||
|
return sha, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadCsvFile read file content into slice.
|
||||||
|
func ReadCsvFile(filepath string) ([][]string, error) {
|
||||||
|
f, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
csvReader := csv.NewReader(f)
|
||||||
|
records, err := csvReader.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteCsvFile write content to target csv file.
|
||||||
|
func WriteCsvFile(filepath string, records [][]string, append bool) error {
|
||||||
|
flag := os.O_RDWR | os.O_CREATE
|
||||||
|
|
||||||
|
if append {
|
||||||
|
flag = flag | os.O_APPEND
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(filepath, flag, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
writer := csv.NewWriter(f)
|
||||||
|
writer.Comma = ','
|
||||||
|
|
||||||
|
return writer.WriteAll(records)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteStringToFile write string to target file.
|
||||||
|
func WriteStringToFile(filepath string, content string, append bool) error {
|
||||||
|
flag := os.O_RDWR | os.O_CREATE
|
||||||
|
if append {
|
||||||
|
flag = flag | os.O_APPEND
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(filepath, flag, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.WriteString(content)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBytesToFile write bytes to target file.
|
||||||
|
func WriteBytesToFile(filepath string, content []byte) error {
|
||||||
|
f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.Write(content)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFile get file reader by a url or a local file.
|
||||||
|
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) {
|
||||||
|
switch {
|
||||||
|
case validator.IsUrl(path):
|
||||||
|
resp, err := http.Get(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, func() {}, err
|
||||||
|
}
|
||||||
|
return resp.Body, func() { resp.Body.Close() }, nil
|
||||||
|
case IsExist(path):
|
||||||
|
reader, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, func() {}, err
|
||||||
|
}
|
||||||
|
return reader, func() { reader.Close() }, nil
|
||||||
|
default:
|
||||||
|
return nil, func() {}, errors.New("unknown file type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package fileutil
|
package fileutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -33,6 +34,27 @@ func TestCreateFile(t *testing.T) {
|
|||||||
os.Remove(f)
|
os.Remove(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateDir(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestCreateDir")
|
||||||
|
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
dirPath := pwd + "/a/"
|
||||||
|
err = CreateDir(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(true, IsExist(dirPath))
|
||||||
|
os.Remove(dirPath)
|
||||||
|
assert.Equal(false, IsExist(dirPath))
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsDir(t *testing.T) {
|
func TestIsDir(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestIsDir")
|
assert := internal.NewAssert(t, "TestIsDir")
|
||||||
|
|
||||||
@@ -79,7 +101,7 @@ func TestListFileNames(t *testing.T) {
|
|||||||
filesInPath, err := ListFileNames("../datetime/")
|
filesInPath, err := ListFileNames("../datetime/")
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
|
|
||||||
expected := []string{"datetime.go", "datetime_test.go"}
|
expected := []string{"conversion.go", "conversion_test.go", "datetime.go", "datetime_test.go"}
|
||||||
assert.Equal(expected, filesInPath)
|
assert.Equal(expected, filesInPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +183,44 @@ func TestZipAndUnZip(t *testing.T) {
|
|||||||
os.RemoveAll(unZipPath)
|
os.RemoveAll(unZipPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestZipAppendEntry(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestZipAppendEntry")
|
||||||
|
|
||||||
|
zipFile := "./text.zip"
|
||||||
|
err := CopyFile("./testdata/file.go.zip", zipFile)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
srcFile := "./text.txt"
|
||||||
|
CreateFile(srcFile)
|
||||||
|
|
||||||
|
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||||
|
|
||||||
|
_, err = file.WriteString("hello\nworld")
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
file.Close()
|
||||||
|
|
||||||
|
err = ZipAppendEntry(srcFile, zipFile)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = ZipAppendEntry("./testdata", zipFile)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
unZipPath := "./unzip"
|
||||||
|
err = UnZip(zipFile, unZipPath)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(true, IsExist("./unzip/text.txt"))
|
||||||
|
assert.Equal(true, IsExist("./unzip/file.go"))
|
||||||
|
assert.Equal(true, IsExist("./unzip/testdata/file.go.zip"))
|
||||||
|
assert.Equal(true, IsExist("./unzip/testdata/test.txt"))
|
||||||
|
|
||||||
|
os.Remove(srcFile)
|
||||||
|
os.Remove(zipFile)
|
||||||
|
os.RemoveAll(unZipPath)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFileMode(t *testing.T) {
|
func TestFileMode(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestFileMode")
|
assert := internal.NewAssert(t, "TestFileMode")
|
||||||
|
|
||||||
@@ -200,3 +260,167 @@ func TestMiMeType(t *testing.T) {
|
|||||||
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
|
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
|
||||||
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
|
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCurrentPath(t *testing.T) {
|
||||||
|
absPath := CurrentPath()
|
||||||
|
t.Log(absPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsZipFile(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsZipFile")
|
||||||
|
|
||||||
|
assert.Equal(false, IsZipFile("./file.go"))
|
||||||
|
assert.Equal(true, IsZipFile("./testdata/file.go.zip"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileSize(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestFileSize")
|
||||||
|
|
||||||
|
size, err := FileSize("./testdata/test.txt")
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(int64(20), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMTime(t *testing.T) {
|
||||||
|
// assert := internal.NewAssert(t, "TestMTime")
|
||||||
|
|
||||||
|
// mtime, err := MTime("./testdata/test.txt")
|
||||||
|
|
||||||
|
// assert.IsNil(err)
|
||||||
|
// assert.Equal(int64(1682478195), mtime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSha(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSha")
|
||||||
|
|
||||||
|
sha1, err := Sha("./testdata/test.txt", 1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
sha256, err := Sha("./testdata/test.txt", 256)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
sha512, err := Sha("./testdata/test.txt", 512)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("dda3cf10c5a6ff6c6659a497bf7261b287af2bc7", sha1)
|
||||||
|
assert.Equal("aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35", sha256)
|
||||||
|
assert.Equal("d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870", sha512)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCsvFile(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestReadCsvFile")
|
||||||
|
|
||||||
|
content, err := ReadCsvFile("./testdata/demo.csv")
|
||||||
|
t.Log(content)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(3, len(content))
|
||||||
|
assert.Equal(3, len(content[0]))
|
||||||
|
assert.Equal("Bob", content[0][0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCsvFile(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestWriteCsvFile")
|
||||||
|
|
||||||
|
csvFilePath := "./testdata/test1.csv"
|
||||||
|
content := [][]string{
|
||||||
|
{"Lili", "22", "female"},
|
||||||
|
{"Jim", "21", "male"},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := WriteCsvFile(csvFilePath, content, false)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
readContent, err := ReadCsvFile(csvFilePath)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(2, len(readContent))
|
||||||
|
assert.Equal(3, len(readContent[0]))
|
||||||
|
assert.Equal("Lili", content[0][0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteStringToFile(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestWriteStringToFile")
|
||||||
|
|
||||||
|
filepath := "./test.txt"
|
||||||
|
|
||||||
|
file, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = WriteStringToFile(filepath, "hello", false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
content1, err := ReadFileToString(filepath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = WriteStringToFile(filepath, " world", true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
content2, err := os.ReadFile(filepath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal("hello", content1)
|
||||||
|
assert.Equal("hello world", string(content2))
|
||||||
|
|
||||||
|
os.Remove(filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteBytesToFile(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestWriteBytesToFile")
|
||||||
|
|
||||||
|
filepath := "./bytes.txt"
|
||||||
|
|
||||||
|
file, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = WriteBytesToFile(filepath, []byte("hello"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := os.ReadFile(filepath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal("hello", string(content))
|
||||||
|
|
||||||
|
os.Remove(filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadFile(t *testing.T) {
|
||||||
|
reader, close, err := ReadFile("https://httpbin.org/robots.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
dat, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
want := `User-agent: *
|
||||||
|
Disallow: /deny
|
||||||
|
`
|
||||||
|
internal.NewAssert(t, "TestReadFile").Equal(want, string(dat))
|
||||||
|
}
|
||||||
|
|||||||
3
fileutil/testdata/demo.csv
vendored
Normal file
3
fileutil/testdata/demo.csv
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Bob, 12, male
|
||||||
|
Duke, 14, male
|
||||||
|
Lucy, 16, female
|
||||||
|
BIN
fileutil/testdata/file.go.zip
vendored
Normal file
BIN
fileutil/testdata/file.go.zip
vendored
Normal file
Binary file not shown.
1
fileutil/testdata/test.txt
vendored
Normal file
1
fileutil/testdata/test.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
this is a test file.
|
||||||
3
fileutil/testdata/test1.csv
vendored
Normal file
3
fileutil/testdata/test1.csv
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Lili,22,female
|
||||||
|
Jim,21,male
|
||||||
|
|
||||||
|
@@ -4,14 +4,176 @@
|
|||||||
// 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
|
"github.com/duke-git/lancet/convertor"
|
||||||
func Comma(v interface{}, symbol string) string {
|
"github.com/duke-git/lancet/strutil"
|
||||||
s := numString(v)
|
"github.com/duke-git/lancet/validator"
|
||||||
dotIndex := strings.Index(s, ".")
|
)
|
||||||
if dotIndex != -1 {
|
|
||||||
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
// 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(value interface{}, symbol string) string {
|
||||||
|
if validator.IsInt(value) {
|
||||||
|
v, err := convertor.ToInt(value)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return symbol + commaInt(v)
|
||||||
}
|
}
|
||||||
return symbol + commaString(s)
|
|
||||||
|
if validator.IsFloat(value) {
|
||||||
|
v, err := convertor.ToFloat(value)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return symbol + commaFloat(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strutil.IsString(value) {
|
||||||
|
v := fmt.Sprintf("%v", value)
|
||||||
|
if validator.IsNumberStr(v) {
|
||||||
|
return symbol + commaStr(v)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pretty data to JSON string.
|
||||||
|
func Pretty(v interface{}) (string, error) {
|
||||||
|
out, err := json.MarshalIndent(v, "", " ")
|
||||||
|
return string(out), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrettyToWriter pretty encode data to writer.
|
||||||
|
func PrettyToWriter(v interface{}, out io.Writer) error {
|
||||||
|
enc := json.NewEncoder(out)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
|
||||||
|
if err := enc.Encode(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://en.wikipedia.org/wiki/Binary_prefix
|
||||||
|
const (
|
||||||
|
// Decimal
|
||||||
|
UnitB = 1
|
||||||
|
UnitKB = 1000
|
||||||
|
UnitMB = 1000 * UnitKB
|
||||||
|
UnitGB = 1000 * UnitMB
|
||||||
|
UnitTB = 1000 * UnitGB
|
||||||
|
UnitPB = 1000 * UnitTB
|
||||||
|
UnitEB = 1000 * UnitPB
|
||||||
|
|
||||||
|
// Binary
|
||||||
|
UnitBiB = 1
|
||||||
|
UnitKiB = 1024
|
||||||
|
UnitMiB = 1024 * UnitKiB
|
||||||
|
UnitGiB = 1024 * UnitMiB
|
||||||
|
UnitTiB = 1024 * UnitGiB
|
||||||
|
UnitPiB = 1024 * UnitTiB
|
||||||
|
UnitEiB = 1024 * UnitPiB
|
||||||
|
)
|
||||||
|
|
||||||
|
// type byteUnitMap map[byte]int64
|
||||||
|
|
||||||
|
var (
|
||||||
|
decimalByteMap = map[string]uint64{
|
||||||
|
"b": UnitB,
|
||||||
|
"kb": UnitKB,
|
||||||
|
"mb": UnitMB,
|
||||||
|
"gb": UnitGB,
|
||||||
|
"tb": UnitTB,
|
||||||
|
"pb": UnitPB,
|
||||||
|
"eb": UnitEB,
|
||||||
|
|
||||||
|
// Without suffix
|
||||||
|
"": UnitB,
|
||||||
|
"k": UnitKB,
|
||||||
|
"m": UnitMB,
|
||||||
|
"g": UnitGB,
|
||||||
|
"t": UnitTB,
|
||||||
|
"p": UnitPB,
|
||||||
|
"e": UnitEB,
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryByteMap = map[string]uint64{
|
||||||
|
"bi": UnitBiB,
|
||||||
|
"kib": UnitKiB,
|
||||||
|
"mib": UnitMiB,
|
||||||
|
"gib": UnitGiB,
|
||||||
|
"tib": UnitTiB,
|
||||||
|
"pib": UnitPiB,
|
||||||
|
"eib": UnitEiB,
|
||||||
|
|
||||||
|
// Without suffix
|
||||||
|
"": UnitBiB,
|
||||||
|
"ki": UnitKiB,
|
||||||
|
"mi": UnitMiB,
|
||||||
|
"gi": UnitGiB,
|
||||||
|
"ti": UnitTiB,
|
||||||
|
"pi": UnitPiB,
|
||||||
|
"ei": UnitEiB,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
decimalByteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
||||||
|
binaryByteUnits = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// DecimalBytes returns a human readable byte size under decimal standard (base 1000)
|
||||||
|
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
|
||||||
|
// Play: https://go.dev/play/p/FPXs1suwRcs
|
||||||
|
func DecimalBytes(size float64, precision ...int) string {
|
||||||
|
p := 5
|
||||||
|
if len(precision) > 0 {
|
||||||
|
p = precision[0] + 1
|
||||||
|
}
|
||||||
|
size, unit := calculateByteSize(size, 1000.0, decimalByteUnits)
|
||||||
|
|
||||||
|
return fmt.Sprintf("%.*g%s", p, size, unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryBytes returns a human-readable byte size under binary standard (base 1024)
|
||||||
|
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
|
||||||
|
func BinaryBytes(size float64, precision ...int) string {
|
||||||
|
p := 5
|
||||||
|
if len(precision) > 0 {
|
||||||
|
p = precision[0] + 1
|
||||||
|
}
|
||||||
|
size, unit := calculateByteSize(size, 1024.0, binaryByteUnits)
|
||||||
|
|
||||||
|
return fmt.Sprintf("%.*g%s", p, size, unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateByteSize(size float64, base float64, byteUnits []string) (float64, string) {
|
||||||
|
i := 0
|
||||||
|
unitsLimit := len(byteUnits) - 1
|
||||||
|
for size >= base && i < unitsLimit {
|
||||||
|
size = size / base
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return size, byteUnits[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseDecimalBytes return the human readable bytes size string into the amount it represents(base 1000).
|
||||||
|
// ParseDecimalBytes("42 MB") -> 42000000, nil
|
||||||
|
func ParseDecimalBytes(size string) (uint64, error) {
|
||||||
|
return parseBytes(size, "decimal")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseBinaryBytes return the human readable bytes size string into the amount it represents(base 1024).
|
||||||
|
// ParseBinaryBytes("42 mib") -> 44040192, nil
|
||||||
|
func ParseBinaryBytes(size string) (uint64, error) {
|
||||||
|
return parseBytes(size, "binary")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,134 @@
|
|||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func commaString(s string) string {
|
// see https://github.com/dustin/go-humanize/blob/master/comma.go
|
||||||
|
func commaInt(v int64) string {
|
||||||
|
sign := ""
|
||||||
|
|
||||||
|
// Min int64 can't be negated to a usable value, so it has to be special cased.
|
||||||
|
if v == math.MinInt64 {
|
||||||
|
return "-9,223,372,036,854,775,808"
|
||||||
|
}
|
||||||
|
|
||||||
|
if v < 0 {
|
||||||
|
sign = "-"
|
||||||
|
v = 0 - v
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := []string{"", "", "", "", "", "", ""}
|
||||||
|
j := len(parts) - 1
|
||||||
|
|
||||||
|
for v > 999 {
|
||||||
|
parts[j] = strconv.FormatInt(v%1000, 10)
|
||||||
|
switch len(parts[j]) {
|
||||||
|
case 2:
|
||||||
|
parts[j] = "0" + parts[j]
|
||||||
|
case 1:
|
||||||
|
parts[j] = "00" + parts[j]
|
||||||
|
}
|
||||||
|
v = v / 1000
|
||||||
|
j--
|
||||||
|
}
|
||||||
|
parts[j] = strconv.Itoa(int(v))
|
||||||
|
return sign + strings.Join(parts[j:], ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
func commaFloat(v float64) string {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
if v < 0 {
|
||||||
|
buf.Write([]byte{'-'})
|
||||||
|
v = 0 - v
|
||||||
|
}
|
||||||
|
|
||||||
|
comma := []byte{','}
|
||||||
|
|
||||||
|
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
|
||||||
|
pos := 0
|
||||||
|
if len(parts[0])%3 != 0 {
|
||||||
|
pos += len(parts[0]) % 3
|
||||||
|
buf.WriteString(parts[0][:pos])
|
||||||
|
buf.Write(comma)
|
||||||
|
}
|
||||||
|
for ; pos < len(parts[0]); pos += 3 {
|
||||||
|
buf.WriteString(parts[0][pos : pos+3])
|
||||||
|
buf.Write(comma)
|
||||||
|
}
|
||||||
|
buf.Truncate(buf.Len() - 1)
|
||||||
|
|
||||||
|
if len(parts) > 1 {
|
||||||
|
buf.Write([]byte{'.'})
|
||||||
|
buf.WriteString(parts[1])
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func commaStr(s string) string {
|
||||||
|
dotIndex := strings.Index(s, ".")
|
||||||
|
if dotIndex != -1 {
|
||||||
|
return commaStrRecursive(s[:dotIndex]) + s[dotIndex:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return commaStrRecursive(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func commaStrRecursive(s string) string {
|
||||||
if len(s) <= 3 {
|
if len(s) <= 3 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func numString(value interface{}) string {
|
// see https://github.com/dustin/go-humanize/blob/master/bytes.go
|
||||||
switch reflect.TypeOf(value).Kind() {
|
func parseBytes(s string, kind string) (uint64, error) {
|
||||||
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
|
lastDigit := 0
|
||||||
return fmt.Sprintf("%v", value)
|
hasComma := false
|
||||||
case reflect.String:
|
for _, r := range s {
|
||||||
{
|
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
|
||||||
sv := fmt.Sprintf("%v", value)
|
break
|
||||||
if strings.Contains(sv, ".") {
|
|
||||||
_, err := strconv.ParseFloat(sv, 64)
|
|
||||||
if err == nil {
|
|
||||||
return sv
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, err := strconv.ParseInt(sv, 10, 64)
|
|
||||||
if err == nil {
|
|
||||||
return sv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default:
|
if r == ',' {
|
||||||
return ""
|
hasComma = true
|
||||||
|
}
|
||||||
|
lastDigit++
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
|
num := s[:lastDigit]
|
||||||
|
if hasComma {
|
||||||
|
num = strings.Replace(num, ",", "", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := strconv.ParseFloat(num, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
|
||||||
|
|
||||||
|
if kind == "decimal" {
|
||||||
|
if m, ok := decimalByteMap[extra]; ok {
|
||||||
|
f *= float64(m)
|
||||||
|
if f >= math.MaxUint64 {
|
||||||
|
return 0, fmt.Errorf("too large: %v", s)
|
||||||
|
}
|
||||||
|
return uint64(f), nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if m, ok := binaryByteMap[extra]; ok {
|
||||||
|
f *= float64(m)
|
||||||
|
if f >= math.MaxUint64 {
|
||||||
|
return 0, fmt.Errorf("too large: %v", s)
|
||||||
|
}
|
||||||
|
return uint64(f), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("unhandled size name: %v", extra)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
"github.com/duke-git/lancet/internal"
|
||||||
@@ -12,12 +13,148 @@ 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,678.9", Comma("12345678.9", ""))
|
||||||
|
|
||||||
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, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPretty(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPretty")
|
||||||
|
|
||||||
|
cases := []interface{}{
|
||||||
|
"",
|
||||||
|
"abc",
|
||||||
|
123,
|
||||||
|
[]string{"a", "b", "c"},
|
||||||
|
map[string]int{"a": 1},
|
||||||
|
struct {
|
||||||
|
Abc int `json:"abc"`
|
||||||
|
}{Abc: 123},
|
||||||
|
}
|
||||||
|
|
||||||
|
expects := []string{
|
||||||
|
"\"\"",
|
||||||
|
`"abc"`,
|
||||||
|
"123",
|
||||||
|
"[\n \"a\",\n \"b\",\n \"c\"\n]",
|
||||||
|
"{\n \"a\": 1\n}",
|
||||||
|
"{\n \"abc\": 123\n}",
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range cases {
|
||||||
|
result, err := Pretty(v)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
t.Log("result -> ", result)
|
||||||
|
assert.Equal(expects[i], result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrettyToWriter(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPrettyToWriter")
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Aage uint `json:"age"`
|
||||||
|
}
|
||||||
|
user := User{Name: "King", Aage: 10000}
|
||||||
|
|
||||||
|
expects := "{\n \"name\": \"King\",\n \"age\": 10000\n}\n"
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := PrettyToWriter(user, buf)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(expects, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecimalBytes(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDecimalBytes")
|
||||||
|
|
||||||
|
assert.Equal("1KB", DecimalBytes(1000))
|
||||||
|
assert.Equal("1.024KB", DecimalBytes(1024))
|
||||||
|
assert.Equal("1.2346MB", DecimalBytes(1234567))
|
||||||
|
assert.Equal("1.235MB", DecimalBytes(1234567, 3))
|
||||||
|
assert.Equal("1.123GB", DecimalBytes(float64(1.123*UnitGB)))
|
||||||
|
assert.Equal("2.123TB", DecimalBytes(float64(2.123*UnitTB)))
|
||||||
|
assert.Equal("3.123PB", DecimalBytes(float64(3.123*UnitPB)))
|
||||||
|
assert.Equal("4.123EB", DecimalBytes(float64(4.123*UnitEB)))
|
||||||
|
assert.Equal("1EB", DecimalBytes(float64(1000*UnitPB)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryBytes(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestBinaryBytes")
|
||||||
|
|
||||||
|
assert.Equal("1KiB", BinaryBytes(1024))
|
||||||
|
assert.Equal("1MiB", BinaryBytes(1024*1024))
|
||||||
|
assert.Equal("1.1774MiB", BinaryBytes(1234567))
|
||||||
|
assert.Equal("1.18MiB", BinaryBytes(1234567, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseDecimalBytes(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestParseDecimalBytes")
|
||||||
|
|
||||||
|
cases := map[string]uint64{
|
||||||
|
"12": uint64(12),
|
||||||
|
"12 k": uint64(12000),
|
||||||
|
"12 kb": uint64(12000),
|
||||||
|
"12kb": uint64(12000),
|
||||||
|
"12k": uint64(12000),
|
||||||
|
"12K": uint64(12000),
|
||||||
|
"12KB": uint64(12000),
|
||||||
|
"12 K": uint64(12000),
|
||||||
|
"12 KB": uint64(12000),
|
||||||
|
"12 Kb": uint64(12000),
|
||||||
|
"12 kB": uint64(12000),
|
||||||
|
"12.2 KB": uint64(12200),
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range cases {
|
||||||
|
result, err := ParseDecimalBytes(k)
|
||||||
|
assert.Equal(v, result)
|
||||||
|
assert.IsNil(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := ParseDecimalBytes("12 AB")
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseBinaryBytes(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestParseBinaryBytes")
|
||||||
|
|
||||||
|
cases := map[string]uint64{
|
||||||
|
"12": uint64(12),
|
||||||
|
"12 ki": uint64(12288),
|
||||||
|
"12 kib": uint64(12288),
|
||||||
|
"12kib": uint64(12288),
|
||||||
|
"12ki": uint64(12288),
|
||||||
|
"12KI": uint64(12288),
|
||||||
|
"12KIB": uint64(12288),
|
||||||
|
"12KiB": uint64(12288),
|
||||||
|
"12 Ki": uint64(12288),
|
||||||
|
"12 KiB": uint64(12288),
|
||||||
|
"12 Kib": uint64(12288),
|
||||||
|
"12 kiB": uint64(12288),
|
||||||
|
"12.2 KiB": uint64(12492),
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range cases {
|
||||||
|
result, err := ParseBinaryBytes(k)
|
||||||
|
assert.Equal(v, result)
|
||||||
|
assert.IsNil(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := ParseDecimalBytes("12 AB")
|
||||||
|
assert.IsNotNil(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,3 +113,15 @@ func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
|
|||||||
|
|
||||||
return quit
|
return quit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||||
|
// the functions one by one.
|
||||||
|
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{} {
|
||||||
|
return func(arg interface{}) (result interface{}) {
|
||||||
|
result = arg
|
||||||
|
for _, fn := range funcs {
|
||||||
|
result = fn(result)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -130,3 +130,21 @@ func TestSchedule(t *testing.T) {
|
|||||||
expected := []string{"*", "*", "*", "*", "*"}
|
expected := []string{"*", "*", "*", "*", "*"}
|
||||||
assert.Equal(expected, res)
|
assert.Equal(expected, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPipeline(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPipeline")
|
||||||
|
|
||||||
|
addOne := func(x interface{}) interface{} {
|
||||||
|
return x.(int) + 1
|
||||||
|
}
|
||||||
|
double := func(x interface{}) interface{} {
|
||||||
|
return 2 * x.(int)
|
||||||
|
}
|
||||||
|
square := func(x interface{}) interface{} {
|
||||||
|
return x.(int) * x.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := Pipeline(addOne, double, square)
|
||||||
|
|
||||||
|
assert.Equal(36, f(2))
|
||||||
|
}
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,3 +1,5 @@
|
|||||||
module github.com/duke-git/lancet
|
module github.com/duke-git/lancet
|
||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
|
require golang.org/x/text v0.5.0
|
||||||
|
|||||||
25
go.sum
Normal file
25
go.sum
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
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=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -36,6 +37,52 @@ func (a *Assert) Equal(expected, actual interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EqualValues asserts that two objects are equal or convertable to the same types and equal.
|
||||||
|
// https://github.com/stretchr/testify/assert/assertions.go
|
||||||
|
func (a *Assert) EqualValues(expected, actual interface{}) {
|
||||||
|
if !objectsAreEqualValues(expected, actual) {
|
||||||
|
makeTestFailed(a.T, a.CaseName, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func objectsAreEqualValues(expected, actual interface{}) bool {
|
||||||
|
if objectsAreEqual(expected, actual) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
actualType := reflect.TypeOf(actual)
|
||||||
|
if actualType == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
expectedValue := reflect.ValueOf(expected)
|
||||||
|
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
|
||||||
|
// Attempt comparison after type conversion
|
||||||
|
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func objectsAreEqual(expected, actual interface{}) bool {
|
||||||
|
if expected == nil || actual == nil {
|
||||||
|
return expected == actual
|
||||||
|
}
|
||||||
|
|
||||||
|
exp, ok := expected.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return reflect.DeepEqual(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
act, ok := actual.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if exp == nil || act == nil {
|
||||||
|
return exp == nil && act == nil
|
||||||
|
}
|
||||||
|
return bytes.Equal(exp, act)
|
||||||
|
}
|
||||||
|
|
||||||
// NotEqual check if expected is not equal with actual
|
// NotEqual check if expected is not equal with actual
|
||||||
func (a *Assert) NotEqual(expected, actual interface{}) {
|
func (a *Assert) NotEqual(expected, actual interface{}) {
|
||||||
if compare(expected, actual) == compareEqual {
|
if compare(expected, actual) == compareEqual {
|
||||||
|
|||||||
@@ -90,3 +90,107 @@ func TruncRound(x float64, n int) float64 {
|
|||||||
res, _ := strconv.ParseFloat(newFloat, 64)
|
res, _ := strconv.ParseFloat(newFloat, 64)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AngleToRadian converts angle value to radian value.
|
||||||
|
func AngleToRadian(angle float64) float64 {
|
||||||
|
radian := angle * (math.Pi / 180)
|
||||||
|
return radian
|
||||||
|
}
|
||||||
|
|
||||||
|
// RadianToAngle converts radian value to angle value.
|
||||||
|
func RadianToAngle(radian float64) float64 {
|
||||||
|
angle := radian * (180 / math.Pi)
|
||||||
|
return angle
|
||||||
|
}
|
||||||
|
|
||||||
|
// PointDistance get two points distance.
|
||||||
|
func PointDistance(x1, y1, x2, y2 float64) float64 {
|
||||||
|
a := x1 - x2
|
||||||
|
b := y1 - y2
|
||||||
|
c := math.Pow(a, 2) + math.Pow(b, 2)
|
||||||
|
|
||||||
|
return math.Sqrt(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPrimes checks if number is prime number.
|
||||||
|
func IsPrime(n int) bool {
|
||||||
|
if n < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
|
||||||
|
if n%i == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GCD return greatest common divisor (GCD) of integers.
|
||||||
|
func GCD(integers ...int) int {
|
||||||
|
result := integers[0]
|
||||||
|
|
||||||
|
for k := range integers {
|
||||||
|
result = gcd(integers[k], result)
|
||||||
|
|
||||||
|
if result == 1 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// find greatest common divisor (GCD)
|
||||||
|
func gcd(a, b int) int {
|
||||||
|
if b == 0 {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
return gcd(b, a%b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCM return Least Common Multiple (LCM) of integers.
|
||||||
|
func LCM(integers ...int) int {
|
||||||
|
result := integers[0]
|
||||||
|
|
||||||
|
for k := range integers {
|
||||||
|
result = lcm(integers[k], result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// find Least Common Multiple (LCM) via GCD.
|
||||||
|
func lcm(a, b int) int {
|
||||||
|
if a == 0 || b == 0 {
|
||||||
|
panic("lcm function: provide non zero integers only.")
|
||||||
|
}
|
||||||
|
return a * b / gcd(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cos returns the cosine of the radian argument.
|
||||||
|
func Cos(radian float64, precision ...int) float64 {
|
||||||
|
t := 1.0 / (2.0 * math.Pi)
|
||||||
|
radian *= t
|
||||||
|
radian -= 0.25 + math.Floor(radian+0.25)
|
||||||
|
radian *= 16.0 * (math.Abs(radian) - 0.5)
|
||||||
|
radian += 0.225 * radian * (math.Abs(radian) - 1.0)
|
||||||
|
|
||||||
|
if len(precision) == 1 {
|
||||||
|
return TruncRound(radian, precision[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return TruncRound(radian, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cos returns the sine of the radian argument.
|
||||||
|
func Sin(radian float64, precision ...int) float64 {
|
||||||
|
return Cos((math.Pi / 2) - radian)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log returns the logarithm of base n.
|
||||||
|
func Log(n, base float64) float64 {
|
||||||
|
return math.Log(n) / math.Log(base)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mathutil
|
package mathutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
"github.com/duke-git/lancet/internal"
|
||||||
@@ -70,3 +71,112 @@ func TestTruncRound(t *testing.T) {
|
|||||||
assert.Equal(TruncRound(0.125, 3), float64(0.125))
|
assert.Equal(TruncRound(0.125, 3), float64(0.125))
|
||||||
assert.Equal(TruncRound(33.33333, 2), float64(33.33))
|
assert.Equal(TruncRound(33.33333, 2), float64(33.33))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAngleToRadian(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestAngleToRadian")
|
||||||
|
|
||||||
|
result1 := AngleToRadian(45)
|
||||||
|
result2 := AngleToRadian(90)
|
||||||
|
result3 := AngleToRadian(180)
|
||||||
|
|
||||||
|
assert.Equal(0.7853981633974483, result1)
|
||||||
|
assert.Equal(1.5707963267948966, result2)
|
||||||
|
assert.Equal(3.141592653589793, result3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRadianToAngle(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestAngleToRadian")
|
||||||
|
|
||||||
|
result1 := RadianToAngle(math.Pi)
|
||||||
|
result2 := RadianToAngle(math.Pi / 2)
|
||||||
|
result3 := RadianToAngle(math.Pi / 4)
|
||||||
|
|
||||||
|
assert.Equal(float64(180), result1)
|
||||||
|
assert.Equal(float64(90), result2)
|
||||||
|
assert.Equal(float64(45), result3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPointDistance(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPointDistance")
|
||||||
|
|
||||||
|
result1 := PointDistance(1, 1, 4, 5)
|
||||||
|
|
||||||
|
assert.Equal(float64(5), result1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsPrime(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsPrime")
|
||||||
|
|
||||||
|
assert.Equal(false, IsPrime(-1))
|
||||||
|
assert.Equal(false, IsPrime(0))
|
||||||
|
assert.Equal(false, IsPrime(1))
|
||||||
|
assert.Equal(true, IsPrime(2))
|
||||||
|
assert.Equal(true, IsPrime(3))
|
||||||
|
assert.Equal(false, IsPrime(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGCD(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestGCD")
|
||||||
|
|
||||||
|
assert.Equal(1, GCD(1, 1))
|
||||||
|
assert.Equal(1, GCD(1, -1))
|
||||||
|
assert.Equal(-1, GCD(-1, 1))
|
||||||
|
assert.Equal(-1, GCD(-1, -1))
|
||||||
|
|
||||||
|
assert.Equal(1, GCD(1, 0))
|
||||||
|
assert.Equal(1, GCD(0, 1))
|
||||||
|
assert.Equal(-1, GCD(-1, 0))
|
||||||
|
assert.Equal(-1, GCD(0, -1))
|
||||||
|
|
||||||
|
assert.Equal(1, GCD(1, -2))
|
||||||
|
assert.Equal(1, GCD(-2, 1))
|
||||||
|
assert.Equal(-1, GCD(-1, 2))
|
||||||
|
assert.Equal(-1, GCD(2, -1))
|
||||||
|
|
||||||
|
assert.Equal(-1, GCD(-1, -2))
|
||||||
|
assert.Equal(-1, GCD(-2, -1))
|
||||||
|
|
||||||
|
assert.Equal(-9, GCD(-27, -36))
|
||||||
|
assert.Equal(3, GCD(3, 6, 9))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLCM(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestLCM")
|
||||||
|
|
||||||
|
assert.Equal(1, LCM(1))
|
||||||
|
assert.Equal(-1, LCM(-1))
|
||||||
|
assert.Equal(-1, LCM(1, -1))
|
||||||
|
assert.Equal(1, LCM(-1, 1))
|
||||||
|
assert.Equal(1, LCM(1, 1))
|
||||||
|
assert.Equal(-1, LCM(-1, -1))
|
||||||
|
assert.Equal(2, LCM(1, 2))
|
||||||
|
assert.Equal(18, LCM(3, 6, 9))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCos(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestCos")
|
||||||
|
|
||||||
|
assert.EqualValues(1, Cos(0))
|
||||||
|
assert.EqualValues(-0.447, Cos(90))
|
||||||
|
assert.EqualValues(-0.598, Cos(180))
|
||||||
|
assert.EqualValues(-1, Cos(math.Pi))
|
||||||
|
assert.EqualValues(0, Cos(math.Pi/2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSin(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSin")
|
||||||
|
|
||||||
|
assert.EqualValues(0, Sin(0))
|
||||||
|
assert.EqualValues(0.894, Sin(90))
|
||||||
|
assert.EqualValues(-0.801, Sin(180))
|
||||||
|
assert.EqualValues(0, Sin(math.Pi))
|
||||||
|
assert.EqualValues(1, Sin(math.Pi/2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLog(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestLog")
|
||||||
|
|
||||||
|
assert.EqualValues(3, Log(8, 2))
|
||||||
|
assert.EqualValues(3, TruncRound(Log(27, 3), 0))
|
||||||
|
assert.EqualValues(2.32, TruncRound(Log(5, 2), 2))
|
||||||
|
}
|
||||||
|
|||||||
308
netutil/http.go
308
netutil/http.go
@@ -6,36 +6,48 @@
|
|||||||
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `url` is required.
|
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `url` is required.
|
||||||
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `params` is variable, the order is:
|
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `params` is variable, the order is:
|
||||||
// params[0] is header which type should be http.Header or map[string]string,
|
// params[0] is header which type should be http.Header or map[string]string,
|
||||||
// params[1] is query param which type should be url.Values or map[string]interface{},
|
// params[1] is query string param which type should be url.Values or map[string]string, when content-type header is
|
||||||
|
// multipart/form-data or application/x-www-form-urlencoded
|
||||||
// params[2] is post body which type should be []byte.
|
// params[2] is post body which type should be []byte.
|
||||||
// params[3] is http client which type should be http.Client.
|
// params[3] is http client which type should be http.Client.
|
||||||
package netutil
|
package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/slice"
|
||||||
)
|
)
|
||||||
|
|
||||||
//HttpGet send get http request
|
// HttpGet send get http request
|
||||||
func HttpGet(url string, params ...interface{}) (*http.Response, error) {
|
func HttpGet(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return doHttpRequest(http.MethodGet, url, params...)
|
return doHttpRequest(http.MethodGet, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//HttpPost send post http request
|
// HttpPost send post http request
|
||||||
func HttpPost(url string, params ...interface{}) (*http.Response, error) {
|
func HttpPost(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return doHttpRequest(http.MethodPost, url, params...)
|
return doHttpRequest(http.MethodPost, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//HttpPut send put http request
|
// HttpPut send put http request
|
||||||
func HttpPut(url string, params ...interface{}) (*http.Response, error) {
|
func HttpPut(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return doHttpRequest(http.MethodPut, url, params...)
|
return doHttpRequest(http.MethodPut, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//HttpDelete send delete http request
|
// HttpDelete send delete http request
|
||||||
func HttpDelete(url string, params ...interface{}) (*http.Response, error) {
|
func HttpDelete(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return doHttpRequest(http.MethodDelete, url, params...)
|
return doHttpRequest(http.MethodDelete, url, params...)
|
||||||
}
|
}
|
||||||
@@ -76,3 +88,289 @@ func ConvertMapToQueryString(param map[string]interface{}) string {
|
|||||||
}
|
}
|
||||||
return build.String()
|
return build.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HttpRequest struct {
|
||||||
|
RawURL string
|
||||||
|
Method string
|
||||||
|
Headers http.Header
|
||||||
|
QueryParams url.Values
|
||||||
|
FormData url.Values
|
||||||
|
File *File
|
||||||
|
Body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpClientConfig contains some configurations for http client
|
||||||
|
type HttpClientConfig struct {
|
||||||
|
SSLEnabled bool
|
||||||
|
TLSConfig *tls.Config
|
||||||
|
Compressed bool
|
||||||
|
HandshakeTimeout time.Duration
|
||||||
|
ResponseTimeout time.Duration
|
||||||
|
Verbose bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultHttpClientConfig defalut client config
|
||||||
|
var defaultHttpClientConfig = &HttpClientConfig{
|
||||||
|
Compressed: false,
|
||||||
|
HandshakeTimeout: 20 * time.Second,
|
||||||
|
ResponseTimeout: 40 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpClient is used for sending http request
|
||||||
|
type HttpClient struct {
|
||||||
|
*http.Client
|
||||||
|
TLS *tls.Config
|
||||||
|
Request *http.Request
|
||||||
|
Config HttpClientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHttpClient make a HttpClient instance
|
||||||
|
func NewHttpClient() *HttpClient {
|
||||||
|
client := &HttpClient{
|
||||||
|
Client: &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSHandshakeTimeout: defaultHttpClientConfig.HandshakeTimeout,
|
||||||
|
ResponseHeaderTimeout: defaultHttpClientConfig.ResponseTimeout,
|
||||||
|
DisableCompression: !defaultHttpClientConfig.Compressed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Config: *defaultHttpClientConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHttpClientWithConfig make a HttpClient instance with pass config
|
||||||
|
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient {
|
||||||
|
if config == nil {
|
||||||
|
config = defaultHttpClientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &HttpClient{
|
||||||
|
Client: &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSHandshakeTimeout: config.HandshakeTimeout,
|
||||||
|
ResponseHeaderTimeout: config.ResponseTimeout,
|
||||||
|
DisableCompression: !config.Compressed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Config: *config,
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.SSLEnabled {
|
||||||
|
client.TLS = config.TLSConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendRequest send http request
|
||||||
|
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error) {
|
||||||
|
err := validateRequest(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawUrl := request.RawURL
|
||||||
|
|
||||||
|
req, err := http.NewRequest(request.Method, rawUrl, bytes.NewBuffer(request.Body))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client.setTLS(rawUrl)
|
||||||
|
client.setHeader(req, request.Headers)
|
||||||
|
client.setQueryParam(req, rawUrl, request.QueryParams)
|
||||||
|
|
||||||
|
if request.FormData != nil {
|
||||||
|
if request.File != nil {
|
||||||
|
err = client.setFormData(req, request.FormData, setFile(request.File))
|
||||||
|
} else {
|
||||||
|
err = client.setFormData(req, request.FormData, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Request = req
|
||||||
|
|
||||||
|
resp, err := client.Client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeResponse decode response into target object
|
||||||
|
func (client *HttpClient) DecodeResponse(resp *http.Response, target interface{}) error {
|
||||||
|
if resp == nil {
|
||||||
|
return errors.New("invalid target param")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return json.NewDecoder(resp.Body).Decode(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setTLS set http client transport TLSClientConfig
|
||||||
|
func (client *HttpClient) setTLS(rawUrl string) {
|
||||||
|
if strings.HasPrefix(rawUrl, "https") {
|
||||||
|
if transport, ok := client.Client.Transport.(*http.Transport); ok {
|
||||||
|
transport.TLSClientConfig = client.TLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setHeader set http rquest header
|
||||||
|
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
|
||||||
|
if headers == nil {
|
||||||
|
headers = make(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := headers["Accept"]; !ok {
|
||||||
|
headers["Accept"] = []string{"*/*"}
|
||||||
|
}
|
||||||
|
if _, ok := headers["Accept-Encoding"]; !ok && client.Config.Compressed {
|
||||||
|
headers["Accept-Encoding"] = []string{"deflate, gzip"}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header = headers
|
||||||
|
}
|
||||||
|
|
||||||
|
// setQueryParam set http request query string param
|
||||||
|
func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryParam url.Values) error {
|
||||||
|
if queryParam != nil {
|
||||||
|
if !strings.Contains(reqUrl, "?") {
|
||||||
|
reqUrl = reqUrl + "?" + queryParam.Encode()
|
||||||
|
} else {
|
||||||
|
reqUrl = reqUrl + "&" + queryParam.Encode()
|
||||||
|
}
|
||||||
|
u, err := url.Parse(reqUrl)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.URL = u
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *HttpClient) setFormData(req *http.Request, values url.Values, setFile SetFileFunc) error {
|
||||||
|
if setFile != nil {
|
||||||
|
err := setFile(req, values)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formData := []byte(values.Encode())
|
||||||
|
req.Body = io.NopCloser(bytes.NewReader(formData))
|
||||||
|
req.ContentLength = int64(len(formData))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetFileFunc func(req *http.Request, values url.Values) error
|
||||||
|
|
||||||
|
// File struct is a combination of file attributes
|
||||||
|
type File struct {
|
||||||
|
Content []byte
|
||||||
|
Path string
|
||||||
|
FieldName string
|
||||||
|
FileName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// setFile set parameters for http request formdata file upload
|
||||||
|
func setFile(f *File) SetFileFunc {
|
||||||
|
return func(req *http.Request, values url.Values) error {
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
|
||||||
|
for key, vals := range values {
|
||||||
|
for _, val := range vals {
|
||||||
|
err := writer.WriteField(key, val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.Content != nil {
|
||||||
|
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
part.Write(f.Content)
|
||||||
|
} else if f.Path != "" {
|
||||||
|
file, err := os.Open(f.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(part, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Body = io.NopCloser(body)
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
req.ContentLength = int64(body.Len())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateRequest check if a request has url, and valid method.
|
||||||
|
func validateRequest(req *HttpRequest) error {
|
||||||
|
if req.RawURL == "" {
|
||||||
|
return errors.New("invalid request url")
|
||||||
|
}
|
||||||
|
|
||||||
|
// common HTTP methods
|
||||||
|
methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH",
|
||||||
|
"HEAD", "CONNECT", "OPTIONS", "TRACE"}
|
||||||
|
|
||||||
|
if !slice.Contain(methods, strings.ToUpper(req.Method)) {
|
||||||
|
return errors.New("invalid request method")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructToUrlValues convert struct to url valuse,
|
||||||
|
// only convert the field which is exported and has `json` tag
|
||||||
|
func StructToUrlValues(targetStruct interface{}) url.Values {
|
||||||
|
rv := reflect.ValueOf(targetStruct)
|
||||||
|
rt := reflect.TypeOf(targetStruct)
|
||||||
|
|
||||||
|
if rt.Kind() == reflect.Ptr {
|
||||||
|
rt = rt.Elem()
|
||||||
|
}
|
||||||
|
if rt.Kind() != reflect.Struct {
|
||||||
|
panic(fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", targetStruct))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := url.Values{}
|
||||||
|
|
||||||
|
fieldNum := rt.NumField()
|
||||||
|
pattern := `^[A-Z]`
|
||||||
|
regex := regexp.MustCompile(pattern)
|
||||||
|
for i := 0; i < fieldNum; i++ {
|
||||||
|
name := rt.Field(i).Name
|
||||||
|
tag := rt.Field(i).Tag.Get("json")
|
||||||
|
if regex.MatchString(name) && tag != "" {
|
||||||
|
if strings.Contains(tag, "omitempty") {
|
||||||
|
tag = strings.Split(tag, ",")[0]
|
||||||
|
}
|
||||||
|
result.Add(tag, fmt.Sprintf("%v", rv.Field(i).Interface()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
package netutil
|
package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
"github.com/duke-git/lancet/internal"
|
||||||
@@ -46,6 +52,29 @@ func TestHttpPost(t *testing.T) {
|
|||||||
t.Log("response: ", resp.StatusCode, string(body))
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHttpPostFormData(t *testing.T) {
|
||||||
|
apiUrl := "https://jsonplaceholder.typicode.com/todos"
|
||||||
|
header := map[string]string{
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
// "Content-Type": "multipart/form-data",
|
||||||
|
}
|
||||||
|
|
||||||
|
postData := url.Values{}
|
||||||
|
postData.Add("userId", "1")
|
||||||
|
postData.Add("title", "TestToDo")
|
||||||
|
|
||||||
|
// postData := make(map[string]string)
|
||||||
|
// postData["userId"] = "1"
|
||||||
|
// postData["title"] = "title"
|
||||||
|
|
||||||
|
resp, err := HttpPost(apiUrl, header, nil, postData)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
func TestHttpPut(t *testing.T) {
|
func TestHttpPut(t *testing.T) {
|
||||||
url := "https://jsonplaceholder.typicode.com/todos/1"
|
url := "https://jsonplaceholder.typicode.com/todos/1"
|
||||||
header := map[string]string{
|
header := map[string]string{
|
||||||
@@ -139,3 +168,193 @@ func TestParseResponse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log("response: ", toDoResp)
|
t.Log("response: ", toDoResp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHttpClient_Get(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestHttpClient_Get")
|
||||||
|
|
||||||
|
request := &HttpRequest{
|
||||||
|
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
|
||||||
|
Method: "GET",
|
||||||
|
}
|
||||||
|
|
||||||
|
httpClient := NewHttpClient()
|
||||||
|
resp, err := httpClient.SendRequest(request)
|
||||||
|
if err != nil || resp.StatusCode != 200 {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Todo struct {
|
||||||
|
UserId int `json:"userId"`
|
||||||
|
Id int `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Completed bool `json:"completed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var todo Todo
|
||||||
|
httpClient.DecodeResponse(resp, &todo)
|
||||||
|
|
||||||
|
assert.Equal(1, todo.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHttpClent_Post(t *testing.T) {
|
||||||
|
header := http.Header{}
|
||||||
|
header.Add("Content-Type", "multipart/form-data")
|
||||||
|
|
||||||
|
postData := url.Values{}
|
||||||
|
postData.Add("userId", "1")
|
||||||
|
postData.Add("title", "testItem")
|
||||||
|
|
||||||
|
request := &HttpRequest{
|
||||||
|
RawURL: "https://jsonplaceholder.typicode.com/todos",
|
||||||
|
Method: "POST",
|
||||||
|
Headers: header,
|
||||||
|
FormData: postData,
|
||||||
|
}
|
||||||
|
|
||||||
|
httpClient := NewHttpClient()
|
||||||
|
resp, err := httpClient.SendRequest(request)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStructToUrlValues(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStructToUrlValues")
|
||||||
|
|
||||||
|
type TodoQuery struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
item1 := TodoQuery{
|
||||||
|
Id: 1,
|
||||||
|
UserId: 123,
|
||||||
|
Name: "test",
|
||||||
|
Status: "completed",
|
||||||
|
}
|
||||||
|
queryValues1 := StructToUrlValues(item1)
|
||||||
|
|
||||||
|
assert.Equal("1", queryValues1.Get("id"))
|
||||||
|
assert.Equal("123", queryValues1.Get("userId"))
|
||||||
|
assert.Equal("test", queryValues1.Get("name"))
|
||||||
|
assert.Equal("", queryValues1.Get("status"))
|
||||||
|
|
||||||
|
item2 := TodoQuery{
|
||||||
|
Id: 2,
|
||||||
|
UserId: 456,
|
||||||
|
}
|
||||||
|
queryValues2 := StructToUrlValues(item2)
|
||||||
|
|
||||||
|
assert.Equal("2", queryValues2.Get("id"))
|
||||||
|
assert.Equal("456", queryValues2.Get("userId"))
|
||||||
|
assert.Equal("", queryValues2.Get("name"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleFileRequest(t *testing.T, w http.ResponseWriter, r *http.Request) {
|
||||||
|
err := r.ParseMultipartForm(1024)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key1 := r.FormValue("key1")
|
||||||
|
expectedKey1 := "value1"
|
||||||
|
if key1 != expectedKey1 {
|
||||||
|
t.Fatalf("expected %s, got %s", expectedKey1, key1)
|
||||||
|
}
|
||||||
|
|
||||||
|
key2 := r.FormValue("key2")
|
||||||
|
expectedKey2 := "value2"
|
||||||
|
if key2 != expectedKey2 {
|
||||||
|
t.Fatalf("expected %s, got %s", expectedKey2, key2)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, header, err := r.FormFile("image")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedFileName := "testImage.jpg"
|
||||||
|
if header.Filename != expectedFileName {
|
||||||
|
t.Fatalf("expected %s, got %s", expectedFileName, header.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
content, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedContent := []byte("file content")
|
||||||
|
if !bytes.Equal(content, expectedContent) {
|
||||||
|
t.Fatalf("expected %s, got %s", string(expectedContent), string(content))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendRequestWithFileContent(t *testing.T) {
|
||||||
|
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
handleFileRequest(t, writer, request)
|
||||||
|
})
|
||||||
|
|
||||||
|
server := httptest.NewServer(handler)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client := NewHttpClient()
|
||||||
|
request := &HttpRequest{
|
||||||
|
RawURL: server.URL,
|
||||||
|
Method: "POST",
|
||||||
|
File: &File{Content: []byte("file content"), FieldName: "image", FileName: "testImage.jpg"},
|
||||||
|
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.SendRequest(request)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendRequestWithFilePath(t *testing.T) {
|
||||||
|
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
handleFileRequest(t, writer, request)
|
||||||
|
})
|
||||||
|
|
||||||
|
server := httptest.NewServer(handler)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
tmpFile, err := ioutil.TempFile("", "testImage.jpg")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.Remove(tmpFile.Name())
|
||||||
|
|
||||||
|
tmpFile.Write([]byte("file content"))
|
||||||
|
tmpFile.Close()
|
||||||
|
|
||||||
|
client := NewHttpClient()
|
||||||
|
request := &HttpRequest{
|
||||||
|
RawURL: server.URL,
|
||||||
|
Method: "POST",
|
||||||
|
File: &File{Path: tmpFile.Name(), FieldName: "image", FileName: "testImage.jpg"},
|
||||||
|
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.SendRequest(request)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
148
netutil/net.go
148
netutil/net.go
@@ -1,10 +1,22 @@
|
|||||||
package netutil
|
package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetInternalIp return internal ipv4
|
// GetInternalIp return internal ipv4
|
||||||
@@ -47,6 +59,26 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
|
|||||||
return &ip, nil
|
return &ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRequestPublicIp return the requested public ip
|
||||||
|
func GetRequestPublicIp(req *http.Request) string {
|
||||||
|
var ip string
|
||||||
|
for _, ip = range strings.Split(req.Header.Get("X-Forwarded-For"), ",") {
|
||||||
|
if ip = strings.TrimSpace(ip); ip != "" && !IsInternalIP(net.ParseIP(ip)) {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip = strings.TrimSpace(req.Header.Get("X-Real-Ip")); ip != "" && !IsInternalIP(net.ParseIP(ip)) {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip, _, _ = net.SplitHostPort(req.RemoteAddr); !IsInternalIP(net.ParseIP(ip)) {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
// GetIps return all ipv4 of system
|
// GetIps return all ipv4 of system
|
||||||
func GetIps() []string {
|
func GetIps() []string {
|
||||||
var ips []string
|
var ips []string
|
||||||
@@ -122,3 +154,119 @@ func IsPublicIP(IP net.IP) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsInternalIP verify an ip is intranet or not
|
||||||
|
func IsInternalIP(IP net.IP) bool {
|
||||||
|
if IP.IsLoopback() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ip4 := IP.To4(); ip4 != nil {
|
||||||
|
return ip4[0] == 10 ||
|
||||||
|
(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) ||
|
||||||
|
(ip4[0] == 169 && ip4[1] == 254) ||
|
||||||
|
(ip4[0] == 192 && ip4[1] == 168)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeUrl encode url
|
||||||
|
func EncodeUrl(urlStr string) (string, error) {
|
||||||
|
URL, err := url.Parse(urlStr)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
URL.RawQuery = URL.Query().Encode()
|
||||||
|
|
||||||
|
return URL.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadFile will upload the file to a server.
|
||||||
|
func UploadFile(filepath string, server string) (bool, error) {
|
||||||
|
if !fileutil.IsExist(filepath) {
|
||||||
|
return false, errors.New("file not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo, err := os.Stat(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyBuffer := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(bodyBuffer)
|
||||||
|
|
||||||
|
formFile, err := writer.CreateFormFile("uploadfile", fileInfo.Name())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
srcFile, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(formFile, srcFile)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := writer.FormDataContentType()
|
||||||
|
writer.Close()
|
||||||
|
|
||||||
|
_, err = http.Post(server, contentType, bodyBuffer)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadFile will download the file exist in url to a local file.
|
||||||
|
func DownloadFile(filepath string, url string) error {
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
out, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(out, resp.Body)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPingConnected checks if can ping specified host or not.
|
||||||
|
func IsPingConnected(host string) bool {
|
||||||
|
cmd := exec.Command("ping", host, "-c", "4", "-W", "6")
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
cmd = exec.Command("ping", host, "-n", "4", "-w", "6")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTelnetConnected checks if can telnet specified host or not.
|
||||||
|
func IsTelnetConnected(host string, port string) bool {
|
||||||
|
adder := host + ":" + port
|
||||||
|
conn, err := net.DialTimeout("tcp", adder, 5*time.Second)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -41,6 +42,7 @@ func doHttpRequest(method, reqUrl string, params ...interface{}) (*http.Response
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
|
|
||||||
err := setHeaderAndQueryAndBody(req, reqUrl, params[0], params[1], params[2])
|
err := setHeaderAndQueryAndBody(req, reqUrl, params[0], params[1], params[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -73,37 +75,34 @@ func setHeaderAndQueryParam(req *http.Request, reqUrl string, header, queryParam
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setHeaderAndQueryAndBody(req *http.Request, reqUrl string, header, queryParam, body interface{}) error {
|
func setHeaderAndQueryAndBody(req *http.Request, reqUrl string, header, queryParam, body interface{}) error {
|
||||||
err := setHeader(req, header)
|
if err := setHeader(req, header); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
} else if err = setQueryParam(req, reqUrl, queryParam); err != nil {
|
||||||
err = setQueryParam(req, reqUrl, queryParam)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
} else if err = setBodyByte(req, body); err != nil {
|
||||||
err = setBodyByte(req, body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setHeader(req *http.Request, header interface{}) error {
|
func setHeader(req *http.Request, header interface{}) error {
|
||||||
if header != nil {
|
if header == nil {
|
||||||
switch v := header.(type) {
|
return nil
|
||||||
case map[string]string:
|
}
|
||||||
for k := range v {
|
|
||||||
req.Header.Add(k, v[k])
|
switch v := header.(type) {
|
||||||
}
|
case map[string]string:
|
||||||
case http.Header:
|
for k := range v {
|
||||||
for k, vv := range v {
|
req.Header.Add(k, v[k])
|
||||||
for _, vvv := range vv {
|
|
||||||
req.Header.Add(k, vvv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("header params type should be http.Header or map[string]string")
|
|
||||||
}
|
}
|
||||||
|
case http.Header:
|
||||||
|
for k, vv := range v {
|
||||||
|
for _, vvv := range vv {
|
||||||
|
req.Header.Add(k, vvv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return errors.New("header params type should be http.Header or map[string]string")
|
||||||
}
|
}
|
||||||
|
|
||||||
if host := req.Header.Get("Host"); host != "" {
|
if host := req.Header.Get("Host"); host != "" {
|
||||||
@@ -123,19 +122,22 @@ func setUrl(req *http.Request, reqUrl string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) error {
|
func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) error {
|
||||||
|
if queryParam == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var values url.Values
|
var values url.Values
|
||||||
if queryParam != nil {
|
|
||||||
switch v := queryParam.(type) {
|
switch v := queryParam.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
values = url.Values{}
|
values = url.Values{}
|
||||||
for k := range v {
|
for k := range v {
|
||||||
values.Set(k, fmt.Sprintf("%v", v[k]))
|
values.Set(k, fmt.Sprintf("%v", v[k]))
|
||||||
}
|
|
||||||
case url.Values:
|
|
||||||
values = v
|
|
||||||
default:
|
|
||||||
return errors.New("query params type should be url.Values or map[string]interface{}")
|
|
||||||
}
|
}
|
||||||
|
case url.Values:
|
||||||
|
values = v
|
||||||
|
default:
|
||||||
|
return errors.New("query params type should be url.Values or map[string]interface{}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// set url
|
// set url
|
||||||
@@ -156,14 +158,36 @@ func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setBodyByte(req *http.Request, body interface{}) error {
|
func setBodyByte(req *http.Request, body interface{}) error {
|
||||||
if body != nil {
|
if body == nil {
|
||||||
switch b := body.(type) {
|
return nil
|
||||||
case []byte:
|
}
|
||||||
req.Body = ioutil.NopCloser(bytes.NewReader(b))
|
var bodyReader *bytes.Reader
|
||||||
req.ContentLength = int64(len(b))
|
switch b := body.(type) {
|
||||||
default:
|
case io.Reader:
|
||||||
return errors.New("body type should be []byte")
|
buf := bytes.NewBuffer(nil)
|
||||||
|
if _, err := io.Copy(buf, b); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
req.Body = ioutil.NopCloser(buf)
|
||||||
|
req.ContentLength = int64(buf.Len())
|
||||||
|
case []byte:
|
||||||
|
bodyReader = bytes.NewReader(b)
|
||||||
|
req.Body = ioutil.NopCloser(bodyReader)
|
||||||
|
req.ContentLength = int64(bodyReader.Len())
|
||||||
|
case map[string]interface{}:
|
||||||
|
values := url.Values{}
|
||||||
|
for k := range b {
|
||||||
|
values.Set(k, fmt.Sprintf("%v", b[k]))
|
||||||
|
}
|
||||||
|
bodyReader = bytes.NewReader([]byte(values.Encode()))
|
||||||
|
req.Body = ioutil.NopCloser(bodyReader)
|
||||||
|
req.ContentLength = int64(bodyReader.Len())
|
||||||
|
case url.Values:
|
||||||
|
bodyReader = bytes.NewReader([]byte(b.Encode()))
|
||||||
|
req.Body = ioutil.NopCloser(bodyReader)
|
||||||
|
req.ContentLength = int64(bodyReader.Len())
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid body type: %T", b)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ func TestGetInternalIp(t *testing.T) {
|
|||||||
assert.IsNotNil(ip)
|
assert.IsNotNil(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPublicIpInfo(t *testing.T) {
|
// func TestGetPublicIpInfo(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestGetPublicIpInfo")
|
// assert := internal.NewAssert(t, "TestGetPublicIpInfo")
|
||||||
|
|
||||||
publicIpInfo, err := GetPublicIpInfo()
|
// publicIpInfo, err := GetPublicIpInfo()
|
||||||
assert.IsNil(err)
|
// assert.IsNil(err)
|
||||||
|
|
||||||
t.Logf("public ip info is: %+v \n", *publicIpInfo)
|
// t.Logf("public ip info is: %+v \n", *publicIpInfo)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestIsPublicIP(t *testing.T) {
|
func TestIsPublicIP(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestIsPublicIP")
|
assert := internal.NewAssert(t, "TestIsPublicIP")
|
||||||
@@ -52,3 +52,23 @@ func TestGetMacAddrs(t *testing.T) {
|
|||||||
macAddrs := GetMacAddrs()
|
macAddrs := GetMacAddrs()
|
||||||
t.Log(macAddrs)
|
t.Log(macAddrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsPingConnected(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsPingConnected")
|
||||||
|
|
||||||
|
result1 := IsPingConnected("www.baidu.com")
|
||||||
|
assert.Equal(true, result1)
|
||||||
|
|
||||||
|
result2 := IsPingConnected("www.!@#&&&.com")
|
||||||
|
assert.Equal(false, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTelnetConnected(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestTelnetConnected")
|
||||||
|
|
||||||
|
result1 := IsTelnetConnected("www.baidu.com", "80")
|
||||||
|
assert.Equal(true, result1)
|
||||||
|
|
||||||
|
result2 := IsTelnetConnected("www.baidu.com", "123")
|
||||||
|
assert.Equal(false, result2)
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,17 +12,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RandString generate random string
|
const (
|
||||||
// see https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go
|
NUMERAL = "0123456789"
|
||||||
func RandString(length int) string {
|
LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz"
|
||||||
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
)
|
||||||
|
|
||||||
b := make([]byte, length)
|
func init() {
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
rand.Seed(time.Now().UnixNano())
|
||||||
for i := range b {
|
|
||||||
b[i] = letters[r.Int63()%int64(len(letters))]
|
|
||||||
}
|
|
||||||
return string(b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandInt generate random int between min and max, maybe min, not be max
|
// RandInt generate random int between min and max, maybe min, not be max
|
||||||
@@ -30,11 +28,12 @@ func RandInt(min, max int) int {
|
|||||||
if min == max {
|
if min == max {
|
||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
|
|
||||||
if max < min {
|
if max < min {
|
||||||
min, max = max, min
|
min, max = max, min
|
||||||
}
|
}
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
return r.Intn(max-min) + min
|
return rand.Intn(max-min) + min
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandBytes generate random byte slice
|
// RandBytes generate random byte slice
|
||||||
@@ -50,6 +49,44 @@ func RandBytes(length int) []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandString generate random string
|
||||||
|
func RandString(length int) string {
|
||||||
|
return random(LETTERS, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandUpper generate a random upper case string
|
||||||
|
func RandUpper(length int) string {
|
||||||
|
return random(UPPER_LETTERS, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandLower generate a random lower case string
|
||||||
|
func RandLower(length int) string {
|
||||||
|
return random(LOWER_LETTERS, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandNumeral generate a random numeral string
|
||||||
|
func RandNumeral(length int) string {
|
||||||
|
return random(NUMERAL, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandNumeralOrLetter generate a random numeral or letter string
|
||||||
|
func RandNumeralOrLetter(length int) string {
|
||||||
|
return random(NUMERAL+LETTERS, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// random generate a random string based on given string range
|
||||||
|
func random(s string, length int) string {
|
||||||
|
b := make([]byte, length)
|
||||||
|
|
||||||
|
// fix: https://github.com/duke-git/lancet/issues/75
|
||||||
|
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
|
||||||
|
for i := range b {
|
||||||
|
b[i] = s[rand.Int63()%int64(len(s))]
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
// UUIdV4 generate a random UUID of version 4 according to RFC 4122
|
// UUIdV4 generate a random UUID of version 4 according to RFC 4122
|
||||||
func UUIdV4() (string, error) {
|
func UUIdV4() (string, error) {
|
||||||
uuid := make([]byte, 16)
|
uuid := make([]byte, 16)
|
||||||
@@ -64,3 +101,27 @@ func UUIdV4() (string, error) {
|
|||||||
|
|
||||||
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandUniqueIntSlice generate a slice of random int of length n that do not repeat.
|
||||||
|
func RandUniqueIntSlice(n, min, max int) []int {
|
||||||
|
if min > max {
|
||||||
|
return []int{}
|
||||||
|
}
|
||||||
|
if n > max-min {
|
||||||
|
n = max - min
|
||||||
|
}
|
||||||
|
|
||||||
|
nums := make([]int, n)
|
||||||
|
used := make(map[int]struct{}, n)
|
||||||
|
for i := 0; i < n; {
|
||||||
|
r := RandInt(min, max)
|
||||||
|
if _, use := used[r]; use {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
used[r] = struct{}{}
|
||||||
|
nums[i] = r
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return nums
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,51 @@ func TestRandString(t *testing.T) {
|
|||||||
assert.Equal(true, reg.MatchString(randStr))
|
assert.Equal(true, reg.MatchString(randStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRandUpper(t *testing.T) {
|
||||||
|
pattern := `^[A-Z]+$`
|
||||||
|
reg := regexp.MustCompile(pattern)
|
||||||
|
|
||||||
|
randStr := RandUpper(6)
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestRandUpper")
|
||||||
|
assert.Equal(6, len(randStr))
|
||||||
|
assert.Equal(true, reg.MatchString(randStr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandLower(t *testing.T) {
|
||||||
|
pattern := `^[a-z]+$`
|
||||||
|
reg := regexp.MustCompile(pattern)
|
||||||
|
|
||||||
|
randStr := RandLower(6)
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestRandLower")
|
||||||
|
assert.Equal(6, len(randStr))
|
||||||
|
assert.Equal(true, reg.MatchString(randStr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandNumeral(t *testing.T) {
|
||||||
|
pattern := `^[0-9]+$`
|
||||||
|
reg := regexp.MustCompile(pattern)
|
||||||
|
|
||||||
|
randStr := RandNumeral(12)
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestRandNumeral")
|
||||||
|
assert.Equal(12, len(randStr))
|
||||||
|
assert.Equal(true, reg.MatchString(randStr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandNumeralOrLetter(t *testing.T) {
|
||||||
|
pattern := `^[0-9a-zA-Z]+$`
|
||||||
|
reg := regexp.MustCompile(pattern)
|
||||||
|
|
||||||
|
randStr := RandNumeralOrLetter(10)
|
||||||
|
t.Log(randStr)
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestRandNumeralOrLetter")
|
||||||
|
assert.Equal(10, len(randStr))
|
||||||
|
assert.Equal(true, reg.MatchString(randStr))
|
||||||
|
}
|
||||||
|
|
||||||
func TestRandInt(t *testing.T) {
|
func TestRandInt(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestRandInt")
|
assert := internal.NewAssert(t, "TestRandInt")
|
||||||
|
|
||||||
@@ -60,3 +105,36 @@ func TestUUIdV4(t *testing.T) {
|
|||||||
isUUiDV4 := regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`)
|
isUUiDV4 := regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`)
|
||||||
assert.Equal(true, isUUiDV4.MatchString(uuid))
|
assert.Equal(true, isUUiDV4.MatchString(uuid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRandUniqueIntSlice(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRandUniqueIntSlice")
|
||||||
|
|
||||||
|
r1 := RandUniqueIntSlice(5, 0, 9)
|
||||||
|
assert.Equal(len(r1), 5)
|
||||||
|
if hasDuplicate(r1) {
|
||||||
|
t.Error("hasDuplicate int")
|
||||||
|
}
|
||||||
|
|
||||||
|
r2 := RandUniqueIntSlice(20, 0, 10)
|
||||||
|
assert.Equal(len(r2), 10)
|
||||||
|
if hasDuplicate(r2) {
|
||||||
|
t.Error("hasDuplicate int")
|
||||||
|
}
|
||||||
|
|
||||||
|
r3 := RandUniqueIntSlice(10, 20, 10)
|
||||||
|
assert.Equal(len(r3), 0)
|
||||||
|
|
||||||
|
r4 := RandUniqueIntSlice(0, 20, 10)
|
||||||
|
assert.Equal(len(r4), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasDuplicate(arr []int) bool {
|
||||||
|
elements := make(map[int]bool)
|
||||||
|
for _, v := range arr {
|
||||||
|
if elements[v] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
elements[v] = true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
231
slice/slice.go
231
slice/slice.go
@@ -167,15 +167,15 @@ func Difference(slice1, slice2 interface{}) interface{} {
|
|||||||
// DifferenceBy it accepts iteratee which is invoked for each element of slice
|
// DifferenceBy it accepts iteratee which is invoked for each element of slice
|
||||||
// and values to generate the criterion by which they're compared.
|
// and values to generate the criterion by which they're compared.
|
||||||
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy,
|
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy,
|
||||||
// the iterateeFn function signature should be func(index int, value interface{}) interface{}.
|
// the iteratee function signature should be func(index int, value interface{}) interface{}.
|
||||||
func DifferenceBy(slice interface{}, comparedSlice interface{}, iterateeFn interface{}) interface{} {
|
func DifferenceBy(slice interface{}, comparedSlice interface{}, iteratee interface{}) interface{} {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
smv := sliceValue(comparedSlice)
|
smv := sliceValue(comparedSlice)
|
||||||
fn := functionValue(iterateeFn)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
|
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
|
||||||
panic("function param should be of type func(" + elemType.String() + ")" + elemType.String())
|
panic("iteratee function signature should be func(" + elemType.String() + ")" + elemType.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
slice1 := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len())
|
slice1 := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len())
|
||||||
@@ -203,15 +203,57 @@ func DifferenceBy(slice interface{}, comparedSlice interface{}, iterateeFn inter
|
|||||||
return res.Interface()
|
return res.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equal checks if two slices are equal: the same length and all elements' order and value are equal
|
||||||
|
func Equal(slice1, slice2 interface{}) bool {
|
||||||
|
sv1 := sliceValue(slice1)
|
||||||
|
sv2 := sliceValue(slice2)
|
||||||
|
|
||||||
|
if sv1.Type().Elem() != sv2.Type().Elem() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv1.Len() != sv2.Len() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < sv1.Len(); i++ {
|
||||||
|
if sv1.Index(i).Interface() != sv2.Index(i).Interface() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// EqualWith checks if two slices are equal with comparator func
|
||||||
|
func EqualWith(slice1, slice2 interface{}, comparator interface{}) bool {
|
||||||
|
sv1 := sliceValue(slice1)
|
||||||
|
sv2 := sliceValue(slice2)
|
||||||
|
|
||||||
|
fn := functionValue(comparator)
|
||||||
|
// elemType1 := sv1.Type().Elem()
|
||||||
|
// elemType2 := sv2.Type().Elem()
|
||||||
|
// todo: check fn signature: func(a elemType1.Kind(), b elemType2.Kind()) bool
|
||||||
|
|
||||||
|
for i := 0; i < sv1.Len(); i++ {
|
||||||
|
flag := fn.Call([]reflect.Value{sv1.Index(i), sv2.Index(i)})[0]
|
||||||
|
if !flag.Bool() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Every return true if all of the values in the slice pass the predicate function.
|
// Every return true if all of the values in the slice pass the predicate function.
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The iteratee function signature should be func(index int, value interface{}) bool .
|
||||||
func Every(slice, function interface{}) bool {
|
func Every(slice, function interface{}) bool {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(function)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentLength int
|
var currentLength int
|
||||||
@@ -226,14 +268,14 @@ func Every(slice, function interface{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// None return true if all the values in the slice mismatch the criteria
|
// None return true if all the values in the slice mismatch the criteria
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The iteratee function signature should be func(index int, value interface{}) bool .
|
||||||
func None(slice, function interface{}) bool {
|
func None(slice, iteratee interface{}) bool {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentLength int
|
var currentLength int
|
||||||
@@ -248,14 +290,14 @@ func None(slice, function interface{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Some return true if any of the values in the list pass the predicate function.
|
// Some return true if any of the values in the list pass the predicate function.
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The iteratee function signature should be func(index int, value interface{}) bool .
|
||||||
func Some(slice, function interface{}) bool {
|
func Some(slice, iteratee interface{}) bool {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
has := false
|
has := false
|
||||||
@@ -270,14 +312,14 @@ func Some(slice, function interface{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter iterates over elements of slice, returning an slice of all elements `signature` returns truthy for.
|
// Filter iterates over elements of slice, returning an slice of all elements `signature` returns truthy for.
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The iteratee function signature should be func(index int, value interface{}) bool .
|
||||||
func Filter(slice, function interface{}) interface{} {
|
func Filter(slice, iteratee interface{}) interface{} {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
res := reflect.MakeSlice(sv.Type(), 0, 0)
|
res := reflect.MakeSlice(sv.Type(), 0, 0)
|
||||||
@@ -292,14 +334,14 @@ func Filter(slice, function interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Count iterates over elements of slice, returns a count of all matched elements
|
// Count iterates over elements of slice, returns a count of all matched elements
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The iteratee function signature should be func(index int, value interface{}) bool .
|
||||||
func Count(slice, function interface{}) int {
|
func Count(slice, iteratee interface{}) int {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var counter int
|
var counter int
|
||||||
@@ -314,14 +356,14 @@ func Count(slice, function interface{}) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
|
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The iteratee function signature should be func(index int, value interface{}) bool .
|
||||||
func GroupBy(slice, function interface{}) (interface{}, interface{}) {
|
func GroupBy(slice, iteratee interface{}) (interface{}, interface{}) {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
groupB := reflect.MakeSlice(sv.Type(), 0, 0)
|
groupB := reflect.MakeSlice(sv.Type(), 0, 0)
|
||||||
@@ -340,14 +382,14 @@ func GroupBy(slice, function interface{}) (interface{}, interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find iterates over elements of slice, returning the first one that passes a truth test on function.
|
// Find iterates over elements of slice, returning the first one that passes a truth test on function.
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The predicate function signature should be func(index int, value interface{}) bool .
|
||||||
func Find(slice, function interface{}) (interface{}, bool) {
|
func Find(slice, predicate interface{}) (interface{}, bool) {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(predicate)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("predicate function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
index := -1
|
index := -1
|
||||||
@@ -369,13 +411,13 @@ func Find(slice, function interface{}) (interface{}, bool) {
|
|||||||
|
|
||||||
// FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on function.
|
// FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on function.
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The function signature should be func(index int, value interface{}) bool .
|
||||||
func FindLast(slice, function interface{}) (interface{}, bool) {
|
func FindLast(slice, predicate interface{}) (interface{}, bool) {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(predicate)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("predicate function signature should be func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
index := -1
|
index := -1
|
||||||
@@ -420,14 +462,14 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ForEach iterates over elements of slice and invokes function for each element
|
// ForEach iterates over elements of slice and invokes function for each element
|
||||||
// The function signature should be func(index int, value interface{}).
|
// The iteratee function signature should be func(index int, value interface{}).
|
||||||
func ForEach(slice, function interface{}) {
|
func ForEach(slice, iteratee interface{}) {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
|
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + elemType.String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + elemType.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
@@ -436,14 +478,14 @@ func ForEach(slice, function interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map creates an slice of values by running each element of `slice` thru `function`.
|
// Map creates an slice of values by running each element of `slice` thru `function`.
|
||||||
// The function signature should be func(index int, value interface{}) interface{}.
|
// The iteratee function signature should be func(index int, value interface{}) interface{}.
|
||||||
func Map(slice, function interface{}) interface{} {
|
func Map(slice, iteratee interface{}) interface{} {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(iteratee)
|
||||||
|
|
||||||
elemType := sv.Type().Elem()
|
elemType := sv.Type().Elem()
|
||||||
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
|
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
|
||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + elemType.String())
|
panic("iteratee function signature should be func(int, " + elemType.String() + ")" + elemType.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
res := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len())
|
res := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len())
|
||||||
@@ -599,7 +641,6 @@ func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}
|
|||||||
return slice, errors.New("InvalidSliceIndex")
|
return slice, errors.New("InvalidSliceIndex")
|
||||||
}
|
}
|
||||||
|
|
||||||
// value is slice
|
|
||||||
vv := reflect.ValueOf(value)
|
vv := reflect.ValueOf(value)
|
||||||
if vv.Kind() == reflect.Slice {
|
if vv.Kind() == reflect.Slice {
|
||||||
if reflect.TypeOf(slice).Elem() != reflect.TypeOf(value).Elem() {
|
if reflect.TypeOf(slice).Elem() != reflect.TypeOf(value).Elem() {
|
||||||
@@ -609,7 +650,6 @@ func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}
|
|||||||
return v.Interface(), nil
|
return v.Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// value is not slice
|
|
||||||
if reflect.TypeOf(slice).Elem() != reflect.TypeOf(value) {
|
if reflect.TypeOf(slice).Elem() != reflect.TypeOf(value) {
|
||||||
return slice, errors.New("InvalidValueType")
|
return slice, errors.New("InvalidValueType")
|
||||||
}
|
}
|
||||||
@@ -667,21 +707,28 @@ func Unique(slice interface{}) interface{} {
|
|||||||
for i := 0; i < len(temp); i++ {
|
for i := 0; i < len(temp); i++ {
|
||||||
res.Index(i).Set(reflect.ValueOf(temp[i]))
|
res.Index(i).Set(reflect.ValueOf(temp[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.Interface()
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
// if use map filter, the result slice element order is random, not same as origin slice
|
// UniqueBy call iteratee func with every item of slice, then remove duplicated.
|
||||||
//mp := make(map[interface{}]bool)
|
// The iteratee function signature should be func(value interface{}) interface{}.
|
||||||
//for i := 0; i < sv.Len(); i++ {
|
func UniqueBy(slice, iteratee interface{}) interface{} {
|
||||||
// v := sv.Index(i).Interface()
|
sv := sliceValue(slice)
|
||||||
// mp[v] = true
|
fn := functionValue(iteratee)
|
||||||
//}
|
|
||||||
//
|
|
||||||
//var res []interface{}
|
|
||||||
//for k := range mp {
|
|
||||||
// res = append(res, mp[k])
|
|
||||||
//}
|
|
||||||
//return res
|
|
||||||
|
|
||||||
|
if sv.Len() == 0 {
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
res := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len())
|
||||||
|
|
||||||
|
for i := 0; i < sv.Len(); i++ {
|
||||||
|
val := fn.Call([]reflect.Value{sv.Index(i)})[0]
|
||||||
|
res.Index(i).Set(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unique(res.Interface())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons.
|
// Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons.
|
||||||
@@ -860,3 +907,77 @@ func Without(slice interface{}, values ...interface{}) interface{} {
|
|||||||
|
|
||||||
return res.Interface()
|
return res.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexOf returns the index at which the first occurrence of a value is found in a slice or return -1
|
||||||
|
// if the value cannot be found.
|
||||||
|
func IndexOf(slice, value interface{}) int {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
|
||||||
|
for i := 0; i < sv.Len(); i++ {
|
||||||
|
if reflect.DeepEqual(sv.Index(i).Interface(), value) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastIndexOf returns the index at which the last occurrence of a value is found in a slice or return -1
|
||||||
|
// if the value cannot be found.
|
||||||
|
func LastIndexOf(slice, value interface{}) int {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
|
||||||
|
for i := sv.Len() - 1; i > 0; i-- {
|
||||||
|
if reflect.DeepEqual(sv.Index(i).Interface(), value) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSlicePointer returns a pointer to the slices of a variable parameter transformation
|
||||||
|
func ToSlicePointer(value ...interface{}) []*interface{} {
|
||||||
|
out := make([]*interface{}, len(value))
|
||||||
|
for i := range value {
|
||||||
|
out[i] = &value[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSlice returns a slices of a variable parameter transformation
|
||||||
|
func ToSlice(value ...interface{}) interface{} {
|
||||||
|
rv := reflect.ValueOf(value)
|
||||||
|
out := reflect.MakeSlice(rv.Type(), len(value), len(value))
|
||||||
|
for i := range value {
|
||||||
|
out.Index(i).Set(reflect.ValueOf(value[i]))
|
||||||
|
}
|
||||||
|
return out.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendIfAbsent only absent append the value
|
||||||
|
func AppendIfAbsent(slice interface{}, value interface{}) interface{} {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
out := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len())
|
||||||
|
for i := 0; i < sv.Len(); i++ {
|
||||||
|
out.Index(i).Set(sv.Index(i))
|
||||||
|
}
|
||||||
|
if !Contain(slice, value) {
|
||||||
|
out = reflect.Append(out, reflect.ValueOf(value))
|
||||||
|
}
|
||||||
|
return out.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendIfAbsent only absent append the value
|
||||||
|
func Join(slice interface{}, separator string) string {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
|
||||||
|
strs := make([]string, sv.Len())
|
||||||
|
|
||||||
|
for i := 0; i < sv.Len(); i++ {
|
||||||
|
strs[i] = fmt.Sprint(sv.Index(i).Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(strs, separator)
|
||||||
|
}
|
||||||
|
|||||||
@@ -73,6 +73,30 @@ func TestConcat(t *testing.T) {
|
|||||||
assert.Equal([]int{1, 2, 3, 4, 5}, Concat([]int{1, 2, 3}, []int{4}, 5))
|
assert.Equal([]int{1, 2, 3, 4, 5}, Concat([]int{1, 2, 3}, []int{4}, 5))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEqual(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestEqual")
|
||||||
|
|
||||||
|
slice1 := []int{1, 2, 3}
|
||||||
|
slice2 := []int{1, 2, 3}
|
||||||
|
slice3 := []int{3, 2, 1}
|
||||||
|
|
||||||
|
assert.Equal(true, Equal(slice1, slice2))
|
||||||
|
assert.Equal(false, Equal(slice1, slice3))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEqualWith(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestEqualWith")
|
||||||
|
|
||||||
|
slice1 := []int{1, 2, 3}
|
||||||
|
slice2 := []int{2, 4, 6}
|
||||||
|
|
||||||
|
isDouble := func(a, b int) bool {
|
||||||
|
return b == a*2
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(true, EqualWith(slice1, slice2, isDouble))
|
||||||
|
}
|
||||||
|
|
||||||
func TestEvery(t *testing.T) {
|
func TestEvery(t *testing.T) {
|
||||||
nums := []int{1, 2, 3, 5}
|
nums := []int{1, 2, 3, 5}
|
||||||
isEven := func(i, num int) bool {
|
isEven := func(i, num int) bool {
|
||||||
@@ -394,6 +418,15 @@ func TestUnique(t *testing.T) {
|
|||||||
assert.Equal([]string{"a", "b", "c"}, Unique([]string{"a", "a", "b", "c"}))
|
assert.Equal([]string{"a", "b", "c"}, Unique([]string{"a", "a", "b", "c"}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUniqueBy(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestUniqueBy")
|
||||||
|
|
||||||
|
actual := UniqueBy([]int{1, 2, 3, 4, 5, 6}, func(val int) int {
|
||||||
|
return val % 4
|
||||||
|
})
|
||||||
|
assert.Equal([]int{1, 2, 3, 0}, actual)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnion(t *testing.T) {
|
func TestUnion(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestUnion")
|
assert := internal.NewAssert(t, "TestUnion")
|
||||||
|
|
||||||
@@ -543,3 +576,63 @@ func TestShuffle(t *testing.T) {
|
|||||||
assert.Equal(true, Contain(res, 4))
|
assert.Equal(true, Contain(res, 4))
|
||||||
assert.Equal(true, Contain(res, 5))
|
assert.Equal(true, Contain(res, 5))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIndexOf(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIndexOf")
|
||||||
|
|
||||||
|
arr := []string{"a", "a", "b", "c"}
|
||||||
|
assert.Equal(0, IndexOf(arr, "a"))
|
||||||
|
assert.Equal(-1, IndexOf(arr, "d"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLastIndexOf(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestLastIndexOf")
|
||||||
|
|
||||||
|
arr := []string{"a", "a", "b", "c"}
|
||||||
|
assert.Equal(1, LastIndexOf(arr, "a"))
|
||||||
|
assert.Equal(-1, LastIndexOf(arr, "d"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToSlice(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToSlice")
|
||||||
|
|
||||||
|
str1 := "a"
|
||||||
|
str2 := "b"
|
||||||
|
out1 := ToSlice(str1)
|
||||||
|
out2 := ToSlice(str1, str2)
|
||||||
|
|
||||||
|
assert.Equal([]string{"a"}, StringSlice(out1))
|
||||||
|
assert.Equal([]string{"a", "b"}, StringSlice(out2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToSlicePointer(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToSlicePointer")
|
||||||
|
|
||||||
|
var str1 interface{}
|
||||||
|
str1 = "a"
|
||||||
|
var str2 interface{}
|
||||||
|
str2 = "b"
|
||||||
|
|
||||||
|
assert.Equal([]*interface{}{&str1}, ToSlicePointer(str1))
|
||||||
|
assert.Equal([]*interface{}{&str1, &str2}, ToSlicePointer(str1, str2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendIfAbsent(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestToAppendIfAbsent")
|
||||||
|
|
||||||
|
str1 := []string{"a", "b"}
|
||||||
|
assert.Equal([]string{"a", "b"}, AppendIfAbsent(str1, "a"))
|
||||||
|
assert.Equal([]string{"a", "b", "c"}, AppendIfAbsent(str1, "c"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJoin(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestJoin")
|
||||||
|
|
||||||
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
result1 := Join(nums, ",")
|
||||||
|
result2 := Join(nums, "-")
|
||||||
|
|
||||||
|
assert.Equal("1,2,3,4,5", result1)
|
||||||
|
assert.Equal("1-2-3-4-5", result2)
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,53 +5,44 @@
|
|||||||
package strutil
|
package strutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 ""
|
|
||||||
}
|
|
||||||
|
|
||||||
res := ""
|
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
|
|
||||||
}
|
|
||||||
res += string(vv)
|
|
||||||
} else {
|
} else {
|
||||||
res += Capitalize(v)
|
builder.WriteString(Capitalize(str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
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.
|
||||||
@@ -78,86 +69,54 @@ func LowerFirst(s string) string {
|
|||||||
return string(r) + s[size:]
|
return string(r) + s[size:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// PadEnd pads string on the right side if it's shorter than size.
|
// PadStart pads string on the left and right side if it's shorter than size.
|
||||||
// Padding characters are truncated if they exceed size.
|
// Padding characters are truncated if they exceed size.
|
||||||
func PadEnd(source string, size int, padStr string) string {
|
func Pad(source string, size int, padStr string) string {
|
||||||
len1 := len(source)
|
return padAtPosition(source, size, padStr, 0)
|
||||||
len2 := len(padStr)
|
|
||||||
|
|
||||||
if len1 >= size {
|
|
||||||
return source
|
|
||||||
}
|
|
||||||
|
|
||||||
fill := ""
|
|
||||||
if len2 >= size-len1 {
|
|
||||||
fill = padStr[0 : size-len1]
|
|
||||||
} else {
|
|
||||||
fill = strings.Repeat(padStr, size-len1)
|
|
||||||
}
|
|
||||||
return source + fill[0:size-len1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PadStart pads string on the left side if it's shorter than size.
|
// PadStart pads string on the left side if it's shorter than size.
|
||||||
// Padding characters are truncated if they exceed size.
|
// Padding characters are truncated if they exceed size.
|
||||||
func PadStart(source string, size int, padStr string) string {
|
func PadStart(source string, size int, padStr string) string {
|
||||||
len1 := len(source)
|
return padAtPosition(source, size, padStr, 1)
|
||||||
len2 := len(padStr)
|
}
|
||||||
|
|
||||||
if len1 >= size {
|
// PadEnd pads string on the right side if it's shorter than size.
|
||||||
return source
|
// Padding characters are truncated if they exceed size.
|
||||||
}
|
func PadEnd(source string, size int, padStr string) string {
|
||||||
|
return padAtPosition(source, size, padStr, 2)
|
||||||
fill := ""
|
|
||||||
if len2 >= size-len1 {
|
|
||||||
fill = padStr[0 : size-len1]
|
|
||||||
} else {
|
|
||||||
fill = strings.Repeat(padStr, size-len1)
|
|
||||||
}
|
|
||||||
return fill[0:size-len1] + source
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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|_]+`)
|
// UpperKebabCase covert string to upper KEBAB-CASE
|
||||||
blankSpace := " "
|
// non letters and numbers will be ignored
|
||||||
match := regex.ReplaceAllString(s, blankSpace)
|
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO-1-1-BAR"
|
||||||
rs := strings.Split(match, blankSpace)
|
func UpperKebabCase(s string) string {
|
||||||
|
result := splitIntoStrings(s, true)
|
||||||
var res []string
|
return strings.Join(result, "-")
|
||||||
for _, v := range rs {
|
|
||||||
splitWords := splitWordsToLower(v)
|
|
||||||
if len(splitWords) > 0 {
|
|
||||||
res = append(res, splitWords...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(res, "-")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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|_]+`)
|
// UpperSnakeCase covert string to upper SNAKE_CASE
|
||||||
blankSpace := " "
|
// non letters and numbers will be ignored
|
||||||
match := regex.ReplaceAllString(s, blankSpace)
|
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO_1_1_BAR"
|
||||||
rs := strings.Split(match, blankSpace)
|
func UpperSnakeCase(s string) string {
|
||||||
|
result := splitIntoStrings(s, true)
|
||||||
var res []string
|
return strings.Join(result, "_")
|
||||||
for _, v := range rs {
|
|
||||||
splitWords := splitWordsToLower(v)
|
|
||||||
if len(splitWords) > 0 {
|
|
||||||
res = append(res, splitWords...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(res, "_")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before create substring in source string before position when char first appear
|
// Before create substring in source string before position when char first appear
|
||||||
@@ -209,8 +168,8 @@ func IsString(v interface{}) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReverseStr return string whose char order is reversed to the given string
|
// Reverse return string whose char order is reversed to the given string
|
||||||
func ReverseStr(s string) string {
|
func Reverse(s string) string {
|
||||||
r := []rune(s)
|
r := []rune(s)
|
||||||
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
|
||||||
r[i], r[j] = r[j], r[i]
|
r[i], r[j] = r[j], r[i]
|
||||||
@@ -248,3 +207,318 @@ func Unwrap(str string, wrapToken string) string {
|
|||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitEx split a given string whether the result contains empty string
|
||||||
|
func SplitEx(s, sep string, removeEmptyString bool) []string {
|
||||||
|
if sep == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
n := strings.Count(s, sep) + 1
|
||||||
|
a := make([]string, n)
|
||||||
|
n--
|
||||||
|
i := 0
|
||||||
|
sepSave := 0
|
||||||
|
ignore := false
|
||||||
|
|
||||||
|
for i < n {
|
||||||
|
m := strings.Index(s, sep)
|
||||||
|
if m < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ignore = false
|
||||||
|
if removeEmptyString {
|
||||||
|
if s[:m+sepSave] == "" {
|
||||||
|
ignore = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ignore {
|
||||||
|
a[i] = s[:m+sepSave]
|
||||||
|
s = s[m+len(sep):]
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
s = s[m+len(sep):]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret []string
|
||||||
|
if removeEmptyString {
|
||||||
|
if s != "" {
|
||||||
|
a[i] = s
|
||||||
|
ret = a[:i+1]
|
||||||
|
} else {
|
||||||
|
ret = a[:i]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a[i] = s
|
||||||
|
ret = a[:i+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitWords splits a string into words, word only contains alphabetic characters.
|
||||||
|
func SplitWords(s string) []string {
|
||||||
|
var word string
|
||||||
|
var words []string
|
||||||
|
var r rune
|
||||||
|
var size, pos int
|
||||||
|
|
||||||
|
isWord := false
|
||||||
|
|
||||||
|
for len(s) > 0 {
|
||||||
|
r, size = utf8.DecodeRuneInString(s)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isLetter(r):
|
||||||
|
if !isWord {
|
||||||
|
isWord = true
|
||||||
|
word = s
|
||||||
|
pos = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case isWord && (r == '\'' || r == '-'):
|
||||||
|
// is word
|
||||||
|
|
||||||
|
default:
|
||||||
|
if isWord {
|
||||||
|
isWord = false
|
||||||
|
words = append(words, word[:pos])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += size
|
||||||
|
s = s[size:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if isWord {
|
||||||
|
words = append(words, word[:pos])
|
||||||
|
}
|
||||||
|
|
||||||
|
return words
|
||||||
|
}
|
||||||
|
|
||||||
|
// WordCount return the number of meaningful word, word only contains alphabetic characters.
|
||||||
|
func WordCount(s string) int {
|
||||||
|
var r rune
|
||||||
|
var size, count int
|
||||||
|
|
||||||
|
isWord := false
|
||||||
|
|
||||||
|
for len(s) > 0 {
|
||||||
|
r, size = utf8.DecodeRuneInString(s)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isLetter(r):
|
||||||
|
if !isWord {
|
||||||
|
isWord = true
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
case isWord && (r == '\'' || r == '-'):
|
||||||
|
// is word
|
||||||
|
|
||||||
|
default:
|
||||||
|
isWord = false
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s[size:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveNonPrintable remove non-printable characters from a string.
|
||||||
|
func RemoveNonPrintable(str string) string {
|
||||||
|
result := strings.Map(func(r rune) rune {
|
||||||
|
if unicode.IsPrint(r) {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}, str)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToBytes converts a string to byte slice without a memory allocation.
|
||||||
|
func StringToBytes(str string) (b []byte) {
|
||||||
|
sh := *(*reflect.StringHeader)(unsafe.Pointer(&str))
|
||||||
|
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||||
|
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesToString converts a byte slice to string without a memory allocation.
|
||||||
|
// Play: todo
|
||||||
|
func BytesToString(bytes []byte) string {
|
||||||
|
return *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBlank checks if a string is whitespace, empty.
|
||||||
|
func IsBlank(str string) bool {
|
||||||
|
if len(str) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// memory copies will occur here, but UTF8 will be compatible
|
||||||
|
runes := []rune(str)
|
||||||
|
for _, r := range runes {
|
||||||
|
if !unicode.IsSpace(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPrefixAny check if a string starts with any of an array of specified strings.
|
||||||
|
func HasPrefixAny(str string, prefixes []string) bool {
|
||||||
|
if len(str) == 0 || len(prefixes) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, prefix := range prefixes {
|
||||||
|
if strings.HasPrefix(str, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasSuffixAny check if a string ends with any of an array of specified strings.
|
||||||
|
func HasSuffixAny(str string, suffixes []string) bool {
|
||||||
|
if len(str) == 0 || len(suffixes) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, suffix := range suffixes {
|
||||||
|
if strings.HasSuffix(str, suffix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexOffset returns the index of the first instance of substr in string after offsetting the string by `idxFrom`,
|
||||||
|
// or -1 if substr is not present in string.
|
||||||
|
func IndexOffset(str string, substr string, idxFrom int) int {
|
||||||
|
if idxFrom > len(str)-1 || idxFrom < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Index(str[idxFrom:], substr) + idxFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplaceWithMap returns a copy of `str`, which is replaced by a map in unordered way, case-sensitively.
|
||||||
|
func ReplaceWithMap(str string, replaces map[string]string) string {
|
||||||
|
for k, v := range replaces {
|
||||||
|
str = strings.ReplaceAll(str, k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitAndTrim splits string `str` by a string `delimiter` to a slice,
|
||||||
|
// and calls Trim to every element of this slice. It ignores the elements
|
||||||
|
// which are empty after Trim.
|
||||||
|
func SplitAndTrim(str, delimiter string, characterMask ...string) []string {
|
||||||
|
result := make([]string, 0)
|
||||||
|
|
||||||
|
for _, v := range strings.Split(str, delimiter) {
|
||||||
|
v = Trim(v, characterMask...)
|
||||||
|
if v != "" {
|
||||||
|
result = append(result, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultTrimChars are the characters which are stripped by Trim* functions in default.
|
||||||
|
DefaultTrimChars = string([]byte{
|
||||||
|
'\t', // Tab.
|
||||||
|
'\v', // Vertical tab.
|
||||||
|
'\n', // New line (line feed).
|
||||||
|
'\r', // Carriage return.
|
||||||
|
'\f', // New page.
|
||||||
|
' ', // Ordinary space.
|
||||||
|
0x00, // NUL-byte.
|
||||||
|
0x85, // Delete.
|
||||||
|
0xA0, // Non-breaking space.
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Trim strips whitespace (or other characters) from the beginning and end of a string.
|
||||||
|
// The optional parameter `characterMask` specifies the additional stripped characters.
|
||||||
|
func Trim(str string, characterMask ...string) string {
|
||||||
|
trimChars := DefaultTrimChars
|
||||||
|
|
||||||
|
if len(characterMask) > 0 {
|
||||||
|
trimChars += characterMask[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Trim(str, trimChars)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HideString hide some chars in source string with param `replaceChar`.
|
||||||
|
// replace range is origin[start : end]. [start, end)
|
||||||
|
func HideString(origin string, start, end int, replaceChar string) string {
|
||||||
|
size := len(origin)
|
||||||
|
|
||||||
|
if start > size-1 || start < 0 || end < 0 || start > end {
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
|
||||||
|
if end > size {
|
||||||
|
end = size
|
||||||
|
}
|
||||||
|
|
||||||
|
if replaceChar == "" {
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
|
||||||
|
startStr := origin[0:start]
|
||||||
|
endStr := origin[end:size]
|
||||||
|
|
||||||
|
replaceSize := end - start
|
||||||
|
replaceStr := strings.Repeat(replaceChar, replaceSize)
|
||||||
|
|
||||||
|
return startStr + replaceStr + endStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsAll return true if target string contains all the substrs.
|
||||||
|
func ContainsAll(str string, substrs []string) bool {
|
||||||
|
for _, v := range substrs {
|
||||||
|
if !strings.Contains(str, v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsAny return true if target string contains any one of the substrs.
|
||||||
|
func ContainsAny(str string, substrs []string) bool {
|
||||||
|
for _, v := range substrs {
|
||||||
|
if strings.Contains(str, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
whitespaceRegexMatcher *regexp.Regexp = regexp.MustCompile(`\s`)
|
||||||
|
mutiWhitespaceRegexMatcher *regexp.Regexp = regexp.MustCompile(`[[:space:]]{2,}|[\s\p{Zs}]{2,}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// RemoveWhiteSpace remove whitespace characters from a string.
|
||||||
|
// when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.
|
||||||
|
func RemoveWhiteSpace(str string, repalceAll bool) string {
|
||||||
|
if repalceAll && str != "" {
|
||||||
|
return strings.Join(strings.Fields(str), "")
|
||||||
|
} else if str != "" {
|
||||||
|
str = mutiWhitespaceRegexMatcher.ReplaceAllString(str, " ")
|
||||||
|
str = whitespaceRegexMatcher.ReplaceAllString(str, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(str)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,40 +1,167 @@
|
|||||||
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 res []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):
|
||||||
res = append(res, s)
|
charType = 1
|
||||||
|
case isUpper(r):
|
||||||
|
charType = 2
|
||||||
|
case isDigit(r):
|
||||||
|
charType = 3
|
||||||
|
default:
|
||||||
|
charType = 4
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
}
|
if charType == lastCharType {
|
||||||
for i := 0; i < l; i++ {
|
runes[len(runes)-1] = append(runes[len(runes)-1], r)
|
||||||
if i < l-1 {
|
|
||||||
res = append(res, strings.ToLower(s[upperIndexes[i]:upperIndexes[i+1]]))
|
|
||||||
} else {
|
} else {
|
||||||
res = append(res, strings.ToLower(s[upperIndexes[i]:]))
|
runes = append(runes, []rune{r})
|
||||||
}
|
}
|
||||||
}
|
lastCharType = charType
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// upperIndex get a int slice which elements are all the uppercase char index of a string
|
|
||||||
func upperIndex(s string) []int {
|
|
||||||
var res []int
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
if 64 < s[i] && s[i] < 91 {
|
|
||||||
res = append(res, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(s) > 0 && res != nil && res[0] != 0 {
|
|
||||||
res = append([]int{0}, res...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func padAtPosition(str string, length int, padStr string, position int) string {
|
||||||
|
if len(str) >= length {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
if padStr == "" {
|
||||||
|
padStr = " "
|
||||||
|
}
|
||||||
|
|
||||||
|
length = length - len(str)
|
||||||
|
startPadLen := 0
|
||||||
|
if position == 0 {
|
||||||
|
startPadLen = length / 2
|
||||||
|
} else if position == 1 {
|
||||||
|
startPadLen = length
|
||||||
|
}
|
||||||
|
endPadLen := length - startPadLen
|
||||||
|
|
||||||
|
charLen := len(padStr)
|
||||||
|
leftPad := ""
|
||||||
|
cur := 0
|
||||||
|
for cur < startPadLen {
|
||||||
|
leftPad += string(padStr[cur%charLen])
|
||||||
|
cur++
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = 0
|
||||||
|
rightPad := ""
|
||||||
|
for cur < endPadLen {
|
||||||
|
rightPad += string(padStr[cur%charLen])
|
||||||
|
cur++
|
||||||
|
}
|
||||||
|
|
||||||
|
return leftPad + str + rightPad
|
||||||
|
}
|
||||||
|
|
||||||
|
// isLetter checks r is a letter but not CJK character.
|
||||||
|
func isLetter(r rune) bool {
|
||||||
|
if !unicode.IsLetter(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
// cjk char: /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/
|
||||||
|
|
||||||
|
// hiragana and katakana (Japanese only)
|
||||||
|
case r >= '\u3034' && r < '\u30ff':
|
||||||
|
return false
|
||||||
|
|
||||||
|
// CJK unified ideographs extension A (Chinese, Japanese, and Korean)
|
||||||
|
case r >= '\u3400' && r < '\u4dbf':
|
||||||
|
return false
|
||||||
|
|
||||||
|
// CJK unified ideographs (Chinese, Japanese, and Korean)
|
||||||
|
case r >= '\u4e00' && r < '\u9fff':
|
||||||
|
return false
|
||||||
|
|
||||||
|
// CJK compatibility ideographs (Chinese, Japanese, and Korean)
|
||||||
|
case r >= '\uf900' && r < '\ufaff':
|
||||||
|
return false
|
||||||
|
|
||||||
|
// half-width katakana (Japanese only)
|
||||||
|
case r >= '\uff66' && r < '\uff9f':
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package strutil
|
package strutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
"github.com/duke-git/lancet/internal"
|
||||||
@@ -9,72 +10,178 @@ 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 TestPad(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPad")
|
||||||
|
|
||||||
|
assert.Equal("a ", Pad("a", 2, ""))
|
||||||
|
assert.Equal("a", Pad("a", 1, "b"))
|
||||||
|
assert.Equal("ab", Pad("a", 2, "b"))
|
||||||
|
assert.Equal("mabcdm", Pad("abcd", 6, "m"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPadEnd(t *testing.T) {
|
func TestPadEnd(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestPadEnd")
|
assert := internal.NewAssert(t, "TestPadEnd")
|
||||||
|
|
||||||
|
assert.Equal("a ", PadEnd("a", 2, " "))
|
||||||
assert.Equal("a", PadEnd("a", 1, "b"))
|
assert.Equal("a", PadEnd("a", 1, "b"))
|
||||||
assert.Equal("ab", PadEnd("a", 2, "b"))
|
assert.Equal("ab", PadEnd("a", 2, "b"))
|
||||||
assert.Equal("abcdmn", PadEnd("abcd", 6, "mno"))
|
assert.Equal("abcdmn", PadEnd("abcd", 6, "mno"))
|
||||||
@@ -143,11 +250,11 @@ func TestIsString(t *testing.T) {
|
|||||||
assert.Equal(false, IsString([]string{}))
|
assert.Equal(false, IsString([]string{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReverseStr(t *testing.T) {
|
func TestReverse(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestReverseStr")
|
assert := internal.NewAssert(t, "TestReverse")
|
||||||
|
|
||||||
assert.Equal("cba", ReverseStr("abc"))
|
assert.Equal("cba", Reverse("abc"))
|
||||||
assert.Equal("54321", ReverseStr("12345"))
|
assert.Equal("54321", Reverse("12345"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWrap(t *testing.T) {
|
func TestWrap(t *testing.T) {
|
||||||
@@ -177,3 +284,184 @@ func TestUnwrap(t *testing.T) {
|
|||||||
assert.Equal("***", Unwrap("***", "**"))
|
assert.Equal("***", Unwrap("***", "**"))
|
||||||
assert.Equal("**", Unwrap("**", "**"))
|
assert.Equal("**", Unwrap("**", "**"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSplitEx(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSplitEx")
|
||||||
|
|
||||||
|
assert.Equal([]string{}, SplitEx(" a b c ", "", true))
|
||||||
|
|
||||||
|
assert.Equal([]string{"", "a", "b", "c", ""}, SplitEx(" a b c ", " ", false))
|
||||||
|
assert.Equal([]string{"a", "b", "c"}, SplitEx(" a b c ", " ", true))
|
||||||
|
|
||||||
|
assert.Equal([]string{" a", "b", "c", ""}, SplitEx(" a = b = c = ", " = ", false))
|
||||||
|
assert.Equal([]string{" a", "b", "c"}, SplitEx(" a = b = c = ", " = ", true))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitWords(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSplitWords")
|
||||||
|
|
||||||
|
cases := map[string][]string{
|
||||||
|
"a word": {"a", "word"},
|
||||||
|
"I'am a programmer": {"I'am", "a", "programmer"},
|
||||||
|
"Bonjour, je suis programmeur": {"Bonjour", "je", "suis", "programmeur"},
|
||||||
|
"a -b-c' 'd'e": {"a", "b-c'", "d'e"},
|
||||||
|
"你好,我是一名码农": nil,
|
||||||
|
"こんにちは,私はプログラマーです": nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, SplitWords(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWordCount(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSplitWords")
|
||||||
|
|
||||||
|
cases := map[string]int{
|
||||||
|
"a word": 2, // {"a", "word"},
|
||||||
|
"I'am a programmer": 3, // {"I'am", "a", "programmer"},
|
||||||
|
"Bonjour, je suis programmeur": 4, // {"Bonjour", "je", "suis", "programmeur"},
|
||||||
|
"a -b-c' 'd'e": 3, // {"a", "b-c'", "d'e"},
|
||||||
|
"你好,我是一名码农": 0, // nil,
|
||||||
|
"こんにちは,私はプログラマーです": 0, // nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range cases {
|
||||||
|
assert.Equal(v, WordCount(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveNonPrintable(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRemoveNonPrintable")
|
||||||
|
|
||||||
|
assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n"))
|
||||||
|
assert.Equal("你好😄", RemoveNonPrintable("你好😄"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToBytes(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStringToBytes")
|
||||||
|
str := "abc"
|
||||||
|
bytes := StringToBytes(str)
|
||||||
|
assert.Equal(reflect.DeepEqual(bytes, []byte{'a', 'b', 'c'}), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBytesToString(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestBytesToString")
|
||||||
|
bytes := []byte{'a', 'b', 'c'}
|
||||||
|
str := BytesToString(bytes)
|
||||||
|
assert.Equal(str == "abc", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsBlank(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsBlank")
|
||||||
|
assert.Equal(IsBlank(""), true)
|
||||||
|
assert.Equal(IsBlank("\t\v\f\n"), true)
|
||||||
|
assert.Equal(IsBlank(" 中文"), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasPrefixAny(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestHasPrefixAny")
|
||||||
|
str := "foo bar"
|
||||||
|
prefixes := []string{"fo", "xyz", "hello"}
|
||||||
|
notMatches := []string{"oom", "world"}
|
||||||
|
assert.Equal(HasPrefixAny(str, prefixes), true)
|
||||||
|
assert.Equal(HasPrefixAny(str, notMatches), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasSuffixAny(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestHasSuffixAny")
|
||||||
|
str := "foo bar"
|
||||||
|
suffixes := []string{"bar", "xyz", "hello"}
|
||||||
|
notMatches := []string{"oom", "world"}
|
||||||
|
assert.Equal(HasSuffixAny(str, suffixes), true)
|
||||||
|
assert.Equal(HasSuffixAny(str, notMatches), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexOffset(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIndexOffset")
|
||||||
|
str := "foo bar hello world"
|
||||||
|
assert.Equal(IndexOffset(str, "o", 5), 12)
|
||||||
|
assert.Equal(IndexOffset(str, "o", 0), 1)
|
||||||
|
assert.Equal(IndexOffset(str, "d", len(str)-1), len(str)-1)
|
||||||
|
assert.Equal(IndexOffset(str, "d", len(str)), -1)
|
||||||
|
assert.Equal(IndexOffset(str, "f", -1), -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReplaceWithMap(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestReplaceWithMap")
|
||||||
|
|
||||||
|
str := "ac ab ab ac"
|
||||||
|
replaces := map[string]string{
|
||||||
|
"a": "1",
|
||||||
|
"b": "2",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(str, "ac ab ab ac")
|
||||||
|
assert.Equal(ReplaceWithMap(str, replaces), "1c 12 12 1c")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrim(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestTrim")
|
||||||
|
|
||||||
|
str1 := "$ ab cd $ "
|
||||||
|
|
||||||
|
assert.Equal("$ ab cd $", Trim(str1))
|
||||||
|
assert.Equal("ab cd", Trim(str1, "$"))
|
||||||
|
assert.Equal("abcd", Trim("\nabcd"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitAndTrim(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestTrim")
|
||||||
|
|
||||||
|
str := " a,b, c,d,$1 "
|
||||||
|
|
||||||
|
result1 := SplitAndTrim(str, ",")
|
||||||
|
result2 := SplitAndTrim(str, ",", "$")
|
||||||
|
|
||||||
|
assert.Equal([]string{"a", "b", "c", "d", "$1"}, result1)
|
||||||
|
assert.Equal([]string{"a", "b", "c", "d", "1"}, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHideString(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestTrim")
|
||||||
|
|
||||||
|
str := "13242658976"
|
||||||
|
|
||||||
|
assert.Equal("13242658976", HideString(str, 0, -1, "*"))
|
||||||
|
assert.Equal("13242658976", HideString(str, 0, 0, "*"))
|
||||||
|
assert.Equal("****2658976", HideString(str, 0, 4, "*"))
|
||||||
|
|
||||||
|
assert.Equal("13242658976", HideString(str, 3, 3, "*"))
|
||||||
|
assert.Equal("132*2658976", HideString(str, 3, 4, "*"))
|
||||||
|
assert.Equal("132****8976", HideString(str, 3, 7, "*"))
|
||||||
|
assert.Equal("1324265****", HideString(str, 7, 11, "*"))
|
||||||
|
|
||||||
|
assert.Equal("1324265****", HideString(str, 7, 100, "*"))
|
||||||
|
assert.Equal("13242658976", HideString(str, 100, 100, "*"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainsAll(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestContainsAll")
|
||||||
|
|
||||||
|
assert.Equal(true, ContainsAll("hello world", []string{"hello", "world"}))
|
||||||
|
assert.Equal(true, ContainsAll("hello world", []string{""}))
|
||||||
|
assert.Equal(false, ContainsAll("hello world", []string{"hello", "abc"}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainsAny(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestContainsAny")
|
||||||
|
|
||||||
|
assert.Equal(true, ContainsAny("hello world", []string{"hello", "world"}))
|
||||||
|
assert.Equal(true, ContainsAny("hello world", []string{"hello", "abc"}))
|
||||||
|
assert.Equal(false, ContainsAny("hello world", []string{"123", "abc"}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveWhiteSpace(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRemoveWhiteSpace")
|
||||||
|
|
||||||
|
str := " hello \r\n \t world"
|
||||||
|
|
||||||
|
assert.Equal("", RemoveWhiteSpace("", true))
|
||||||
|
assert.Equal("helloworld", RemoveWhiteSpace(str, true))
|
||||||
|
assert.Equal("hello world", RemoveWhiteSpace(str, false))
|
||||||
|
}
|
||||||
|
|||||||
69
system/os.go
69
system/os.go
@@ -9,6 +9,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Option func(*exec.Cmd)
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsWindows check if current os is windows
|
// IsWindows check if current os is windows
|
||||||
@@ -50,23 +58,70 @@ 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
|
||||||
func ExecCommand(command string) (stdout, stderr string, err error) {
|
// 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, opts ...Option) (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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
if opt != nil {
|
||||||
|
opt(cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
// return bit int (32/64)
|
||||||
|
func GetOsBits() int {
|
||||||
|
return 32 << (^uint(0) >> 63)
|
||||||
|
}
|
||||||
|
|||||||
25
system/os_darwin.go
Normal file
25
system/os_darwin.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//go:build darwin
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithForeground() Option {
|
||||||
|
return func(c *exec.Cmd) {
|
||||||
|
// if c.SysProcAttr == nil {
|
||||||
|
// c.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
// Foreground: true,
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// c.SysProcAttr.Foreground = true
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithWinHide() Option {
|
||||||
|
return func(c *exec.Cmd) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
26
system/os_linux.go
Normal file
26
system/os_linux.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithForeground() Option {
|
||||||
|
return func(c *exec.Cmd) {
|
||||||
|
if c.SysProcAttr == nil {
|
||||||
|
c.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Foreground: true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.SysProcAttr.Foreground = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithWinHide() Option {
|
||||||
|
return func(c *exec.Cmd) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,19 +44,34 @@ 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) {
|
||||||
|
osBits := GetOsBits()
|
||||||
|
switch osBits {
|
||||||
|
case 32, 64:
|
||||||
|
t.Logf("os is %d", osBits)
|
||||||
|
default:
|
||||||
|
t.Error("os is not 32 or 64 bits")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
system/os_windows.go
Normal file
20
system/os_windows.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithWinHide() Option {
|
||||||
|
return func(c *exec.Cmd) {
|
||||||
|
if c.SysProcAttr == nil {
|
||||||
|
c.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
HideWindow: true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.SysProcAttr.HideWindow = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,17 +8,39 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"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})$`)
|
||||||
|
base64URLMatcher *regexp.Regexp = regexp.MustCompile(`^([A-Za-z0-9_-]{4})*([A-Za-z0-9_-]{2}(==)?|[A-Za-z0-9_-]{3}=?)?$`)
|
||||||
|
binMatcher *regexp.Regexp = regexp.MustCompile(`^(0b)?[01]+$`)
|
||||||
|
hexMatcher *regexp.Regexp = regexp.MustCompile(`^(#|0x|0X)?[0-9a-fA-F]+$`)
|
||||||
|
visaMatcher *regexp.Regexp = regexp.MustCompile(`^4[0-9]{12}(?:[0-9]{3})?$`)
|
||||||
|
masterCardMatcher *regexp.Regexp = regexp.MustCompile(`^5[1-5][0-9]{14}$`)
|
||||||
|
americanExpressMatcher *regexp.Regexp = regexp.MustCompile(`^3[47][0-9]{13}$`)
|
||||||
|
unionPay *regexp.Regexp = regexp.MustCompile("^62[0-5]\\d{13,16}$")
|
||||||
|
chinaUnionPay *regexp.Regexp = regexp.MustCompile(`^62[0-9]{14,17}$`)
|
||||||
|
)
|
||||||
|
|
||||||
// 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
|
||||||
@@ -61,11 +83,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
|
||||||
@@ -85,11 +105,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.
|
||||||
@@ -124,8 +142,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, ".") {
|
||||||
@@ -142,64 +158,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.
|
||||||
@@ -258,3 +258,171 @@ func IsWeakPassword(password string) bool {
|
|||||||
|
|
||||||
return (num || letter) && !special
|
return (num || letter) && !special
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsZeroValue checks if value is a zero value
|
||||||
|
func IsZeroValue(value interface{}) bool {
|
||||||
|
if value == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := reflect.ValueOf(value)
|
||||||
|
if !rv.IsValid() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return rv.Len() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !rv.Bool()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return rv.Int() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return rv.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return rv.Float() == 0
|
||||||
|
case reflect.Ptr, reflect.Chan, reflect.Func, reflect.Interface, reflect.Slice, reflect.Map:
|
||||||
|
return rv.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNumberStr check if the value is number(integer, float) or not.
|
||||||
|
func IsNumber(v interface{}) bool {
|
||||||
|
return IsInt(v) || IsFloat(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFloat check if the value is float(float32, float34) or not.
|
||||||
|
func IsFloat(v interface{}) bool {
|
||||||
|
switch v.(type) {
|
||||||
|
case float32, float64:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInt check if the value is integer(int, unit) or not.
|
||||||
|
func IsInt(v interface{}) bool {
|
||||||
|
switch v.(type) {
|
||||||
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsASCII checks if string is all ASCII char.
|
||||||
|
func IsASCII(str string) bool {
|
||||||
|
for i := 0; i < len(str); i++ {
|
||||||
|
if str[i] > unicode.MaxASCII {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPrintable checks if string is all printable chars.
|
||||||
|
func IsPrintable(str string) bool {
|
||||||
|
for _, r := range str {
|
||||||
|
if !unicode.IsPrint(r) {
|
||||||
|
if r == '\n' || r == '\r' || r == '\t' || r == '`' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBin check if a give string is a valid binary value or not.
|
||||||
|
func IsBin(v string) bool {
|
||||||
|
return binMatcher.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsHex check if a give string is a valid hexadecimal value or not.
|
||||||
|
func IsHex(v string) bool {
|
||||||
|
return hexMatcher.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBase64URL check if a give string is a valid URL-safe Base64 encoded string.
|
||||||
|
func IsBase64URL(v string) bool {
|
||||||
|
return base64URLMatcher.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsJWT check if a give string is a valid JSON Web Token (JWT).
|
||||||
|
func IsJWT(v string) bool {
|
||||||
|
strings := strings.Split(v, ".")
|
||||||
|
if len(strings) != 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range strings {
|
||||||
|
if !IsBase64URL(s) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsVisa check if a give string is a valid visa card nubmer or not.
|
||||||
|
func IsVisa(v string) bool {
|
||||||
|
return visaMatcher.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMasterCard check if a give string is a valid master card nubmer or not.
|
||||||
|
func IsMasterCard(v string) bool {
|
||||||
|
return masterCardMatcher.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAmericanExpress check if a give string is a valid american expression card nubmer or not.
|
||||||
|
func IsAmericanExpress(v string) bool {
|
||||||
|
return americanExpressMatcher.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUnionPay check if a give string is a valid union pay nubmer or not.
|
||||||
|
func IsUnionPay(v string) bool {
|
||||||
|
return unionPay.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsChinaUnionPay check if a give string is a valid china union pay nubmer or not.
|
||||||
|
func IsChinaUnionPay(v string) bool {
|
||||||
|
return chinaUnionPay.MatchString(v)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package validator
|
package validator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
"github.com/duke-git/lancet/internal"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsAllUpper(t *testing.T) {
|
func TestIsAllUpper(t *testing.T) {
|
||||||
@@ -279,3 +283,255 @@ func TestIsWeakPassword(t *testing.T) {
|
|||||||
assert.Equal(true, IsWeakPassword("abcABC123"))
|
assert.Equal(true, IsWeakPassword("abcABC123"))
|
||||||
assert.Equal(false, IsWeakPassword("abc123@#$"))
|
assert.Equal(false, IsWeakPassword("abc123@#$"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsZeroValue(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsZeroValue")
|
||||||
|
|
||||||
|
var (
|
||||||
|
zeroPtr *string
|
||||||
|
zeroSlice []int
|
||||||
|
zeroFunc func() string
|
||||||
|
zeroMap map[string]string
|
||||||
|
nilIface interface{}
|
||||||
|
zeroIface fmt.Formatter
|
||||||
|
)
|
||||||
|
zeroValues := []interface{}{
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
int8(0),
|
||||||
|
int16(0),
|
||||||
|
int32(0),
|
||||||
|
int64(0),
|
||||||
|
uint(0),
|
||||||
|
uint8(0),
|
||||||
|
uint16(0),
|
||||||
|
uint32(0),
|
||||||
|
uint64(0),
|
||||||
|
|
||||||
|
0.0,
|
||||||
|
float32(0.0),
|
||||||
|
float64(0.0),
|
||||||
|
|
||||||
|
"",
|
||||||
|
|
||||||
|
// func
|
||||||
|
zeroFunc,
|
||||||
|
|
||||||
|
// array / slice
|
||||||
|
[0]int{},
|
||||||
|
zeroSlice,
|
||||||
|
|
||||||
|
// map
|
||||||
|
zeroMap,
|
||||||
|
|
||||||
|
// interface
|
||||||
|
nilIface,
|
||||||
|
zeroIface,
|
||||||
|
|
||||||
|
// pointer
|
||||||
|
zeroPtr,
|
||||||
|
|
||||||
|
// struct
|
||||||
|
time.Time{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, value := range zeroValues {
|
||||||
|
assert.Equal(true, IsZeroValue(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonZeroIface fmt.Stringer = time.Now()
|
||||||
|
|
||||||
|
nonZeroValues := []interface{}{
|
||||||
|
// bool
|
||||||
|
true,
|
||||||
|
|
||||||
|
// int
|
||||||
|
1,
|
||||||
|
int8(1),
|
||||||
|
int16(1),
|
||||||
|
int32(1),
|
||||||
|
int64(1),
|
||||||
|
uint8(1),
|
||||||
|
uint16(1),
|
||||||
|
uint32(1),
|
||||||
|
uint64(1),
|
||||||
|
|
||||||
|
// float
|
||||||
|
1.0,
|
||||||
|
float32(1.0),
|
||||||
|
float64(1.0),
|
||||||
|
|
||||||
|
// string
|
||||||
|
"test",
|
||||||
|
|
||||||
|
// func
|
||||||
|
time.Now,
|
||||||
|
|
||||||
|
// array / slice
|
||||||
|
[]int{},
|
||||||
|
[]int{42},
|
||||||
|
[1]int{42},
|
||||||
|
|
||||||
|
// map
|
||||||
|
make(map[string]string, 1),
|
||||||
|
|
||||||
|
// interface
|
||||||
|
nonZeroIface,
|
||||||
|
|
||||||
|
// pointer
|
||||||
|
&nonZeroIface,
|
||||||
|
|
||||||
|
// struct
|
||||||
|
time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, value := range nonZeroValues {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsNumber(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsNumber")
|
||||||
|
|
||||||
|
assert.Equal(false, IsNumber(""))
|
||||||
|
assert.Equal(false, IsNumber("3"))
|
||||||
|
assert.Equal(true, IsNumber(0))
|
||||||
|
assert.Equal(true, IsNumber(0.1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsFloat(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsFloat")
|
||||||
|
|
||||||
|
assert.Equal(false, IsFloat(""))
|
||||||
|
assert.Equal(false, IsFloat("3"))
|
||||||
|
assert.Equal(false, IsFloat(0))
|
||||||
|
assert.Equal(true, IsFloat(0.1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsInt(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsInt")
|
||||||
|
|
||||||
|
assert.Equal(false, IsInt(""))
|
||||||
|
assert.Equal(false, IsInt("3"))
|
||||||
|
assert.Equal(false, IsInt(0.1))
|
||||||
|
assert.Equal(true, IsInt(0))
|
||||||
|
assert.Equal(true, IsInt(-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsASCII(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsASCII")
|
||||||
|
|
||||||
|
assert.Equal(true, IsASCII("ABC"))
|
||||||
|
assert.Equal(true, IsASCII("123"))
|
||||||
|
assert.Equal(true, IsASCII(""))
|
||||||
|
assert.Equal(false, IsASCII("😄"))
|
||||||
|
assert.Equal(false, IsASCII("你好"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsPrintable(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsPrintable")
|
||||||
|
|
||||||
|
assert.Equal(true, IsPrintable("ABC"))
|
||||||
|
assert.Equal(true, IsPrintable("{id: 123}"))
|
||||||
|
assert.Equal(true, IsPrintable(""))
|
||||||
|
assert.Equal(true, IsPrintable("😄"))
|
||||||
|
assert.Equal(false, IsPrintable("\u0000"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsBin(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsBin")
|
||||||
|
|
||||||
|
assert.Equal(true, IsBin("0101"))
|
||||||
|
assert.Equal(true, IsBin("0b1101"))
|
||||||
|
|
||||||
|
assert.Equal(false, IsBin("b1101"))
|
||||||
|
assert.Equal(false, IsBin("1201"))
|
||||||
|
assert.Equal(false, IsBin(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsHex(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsHex")
|
||||||
|
|
||||||
|
assert.Equal(true, IsHex("ABCDE"))
|
||||||
|
assert.Equal(true, IsHex("abcde"))
|
||||||
|
assert.Equal(true, IsHex("0xabcde"))
|
||||||
|
assert.Equal(true, IsHex("0Xabcde"))
|
||||||
|
assert.Equal(true, IsHex("#abcde"))
|
||||||
|
|
||||||
|
assert.Equal(false, IsHex("cdfeg"))
|
||||||
|
assert.Equal(false, IsHex("0xcdfeg"))
|
||||||
|
assert.Equal(false, IsHex(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsBase64URL(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsBase64URL")
|
||||||
|
|
||||||
|
assert.Equal(true, IsBase64URL("SAGsbG8sIHdvcmxkIQ"))
|
||||||
|
assert.Equal(true, IsBase64URL("SAGsbG8sIHdvcmxkIQ=="))
|
||||||
|
|
||||||
|
assert.Equal(false, IsBase64URL("SAGsbG8sIHdvcmxkIQ="))
|
||||||
|
assert.Equal(false, IsBase64URL("SAGsbG8sIHdvcmxkIQ==="))
|
||||||
|
// assert.Equal(false, IsBase64URL(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsJWT(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsJWT")
|
||||||
|
|
||||||
|
assert.Equal(true, IsJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibWVzc2FnZSI6IlB1dGluIGlzIGFic29sdXRlIHNoaXQiLCJpYXQiOjE1MTYyMzkwMjJ9.wkLWA5GtCpWdxNOrRse8yHZgORDgf8TpJp73WUQb910"))
|
||||||
|
assert.Equal(false, IsJWT("abc"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsVisa(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsVisa")
|
||||||
|
|
||||||
|
assert.Equal(true, IsVisa("4111111111111111"))
|
||||||
|
assert.Equal(false, IsVisa("123"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsMasterCard(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsMasterCard")
|
||||||
|
|
||||||
|
assert.Equal(true, IsMasterCard("5425233430109903"))
|
||||||
|
assert.Equal(false, IsMasterCard("4111111111111111"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsAmericanExpress(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsAmericanExpress")
|
||||||
|
|
||||||
|
assert.Equal(true, IsAmericanExpress("342883359122187"))
|
||||||
|
assert.Equal(false, IsAmericanExpress("3782822463100007"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsUnionPay(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsUnionPay")
|
||||||
|
|
||||||
|
assert.Equal(true, IsUnionPay("6221263430109903"))
|
||||||
|
assert.Equal(false, IsUnionPay("3782822463100007"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsChinaUnionPay(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestIsChinaUnionPay")
|
||||||
|
|
||||||
|
assert.Equal(true, IsChinaUnionPay("6250941006528599"))
|
||||||
|
assert.Equal(false, IsChinaUnionPay("3782822463100007"))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user