mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-09 07:02:29 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d910af24e0 | ||
|
|
5fc21330da | ||
|
|
928e3a390d | ||
|
|
48519aba2b | ||
|
|
97ea636e9e | ||
|
|
f82f49a4c2 | ||
|
|
0fc8733915 | ||
|
|
44022c5861 | ||
|
|
ec0222c5b1 | ||
|
|
76b82a2fa1 | ||
|
|
d9dc2993b3 | ||
|
|
ae42a9fdff | ||
|
|
f37e55d9f1 | ||
|
|
d920a51988 | ||
|
|
561c42a24e | ||
|
|
12d74489d5 | ||
|
|
4959f26003 | ||
|
|
eb683a33d2 | ||
|
|
0e63489e9e | ||
|
|
d9e318550a | ||
|
|
993b0e6023 | ||
|
|
7cf358a0ec | ||
|
|
b85545c584 | ||
|
|
c3c6c92cd4 | ||
|
|
8587abc977 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,6 +5,9 @@ cryptor/*.txt
|
|||||||
fileutil/*.txt
|
fileutil/*.txt
|
||||||
fileutil/*.zip
|
fileutil/*.zip
|
||||||
fileutil/*.link
|
fileutil/*.link
|
||||||
|
fileutil/tempdir
|
||||||
fileutil/unzip/*
|
fileutil/unzip/*
|
||||||
slice/testdata/*
|
slice/testdata/*
|
||||||
cryptor/*.pem
|
cryptor/*.pem
|
||||||
|
docs/node_modules
|
||||||
|
docs/.vitepress
|
||||||
47
README.md
47
README.md
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
[](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)
|
||||||
@@ -96,6 +96,7 @@ import "github.com/duke-git/lancet/convertor"
|
|||||||
- [ToJson](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToJson)
|
- [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)
|
- [ToString](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToString)
|
||||||
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#StructToMap)
|
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#StructToMap)
|
||||||
|
- [MapToStruct](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#MapToStruct)
|
||||||
- [EncodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#EncodeByte)
|
- [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)
|
- [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)
|
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DeepClone)
|
||||||
@@ -103,6 +104,10 @@ import "github.com/duke-git/lancet/convertor"
|
|||||||
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToInterface)
|
- [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)
|
- [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)
|
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#GbkToUtf8)
|
||||||
|
- [ToStdBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToStdBase64)
|
||||||
|
- [ToUrlBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToUrlBase64)
|
||||||
|
- [ToRawStdBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToRawStdBase64)
|
||||||
|
- [ToRawUrlBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToRawUrlBase64)
|
||||||
|
|
||||||
### 3. Cryptor package is for data encryption and decryption.
|
### 3. Cryptor package is for data encryption and decryption.
|
||||||
|
|
||||||
@@ -133,18 +138,30 @@ import "github.com/duke-git/lancet/cryptor"
|
|||||||
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesOfbEncrypt)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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.
|
### 4. Datetime package supports date and time format and compare.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -188,6 +205,11 @@ import "github.com/duke-git/lancet/datetime"
|
|||||||
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BetweenSeconds)
|
- [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)
|
- [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)
|
- [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.
|
### 5. Fileutil package implements some basic functions for file operations.
|
||||||
|
|
||||||
@@ -220,8 +242,10 @@ import "github.com/duke-git/lancet/fileutil"
|
|||||||
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Sha)
|
- [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)
|
- [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)
|
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteCsvFile)
|
||||||
|
- [WriteMapsToCsv](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteMapsToCsv)
|
||||||
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteStringToFile)
|
- [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)
|
- [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)
|
||||||
|
|
||||||
### 6. Formatter contains some functions for data formatting.
|
### 6. Formatter contains some functions for data formatting.
|
||||||
|
|
||||||
@@ -272,6 +296,10 @@ import "github.com/duke-git/lancet/mathutil"
|
|||||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RoundToFloat)
|
- [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)
|
- [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)
|
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#TruncRound)
|
||||||
|
- [CeilToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#CeilToFloat)
|
||||||
|
- [CeilToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#CeilToString)
|
||||||
|
- [FloorToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#FloorToFloat)
|
||||||
|
- [FloorToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#FloorToString)
|
||||||
- [AngleToRadian](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#AngleToRadian)
|
- [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)
|
- [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)
|
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#PointDistance)
|
||||||
@@ -390,6 +418,7 @@ import "github.com/duke-git/lancet/slice"
|
|||||||
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Union)
|
- [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)
|
- [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)
|
- [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.
|
### 13. Strutil package contains some functions to manipulate string.
|
||||||
|
|
||||||
@@ -435,6 +464,10 @@ import "github.com/duke-git/lancet/strutil"
|
|||||||
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitAndTrim)
|
- [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)
|
- [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)
|
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#RemoveWhiteSpace)
|
||||||
|
- [SubInBetween](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SubInBetween)
|
||||||
|
- [HammingDistance](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HammingDistance)
|
||||||
|
|
||||||
|
|
||||||
### 14. System package contain some functions about os, runtime, shell command.
|
### 14. System package contain some functions about os, runtime, shell command.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -494,6 +527,16 @@ import "github.com/duke-git/lancet/validator"
|
|||||||
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsGBK)
|
- [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)
|
- [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)
|
- [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
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
[](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)
|
||||||
@@ -95,6 +95,7 @@ import "github.com/duke-git/lancet/convertor"
|
|||||||
- [ToJson](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToJson)
|
- [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)
|
- [ToString](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToString)
|
||||||
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#StructToMap)
|
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#StructToMap)
|
||||||
|
- [MapToStruct](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#MapToStruct)
|
||||||
- [EncodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#EncodeByte)
|
- [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)
|
- [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)
|
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DeepClone)
|
||||||
@@ -102,6 +103,12 @@ import "github.com/duke-git/lancet/convertor"
|
|||||||
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInterface)
|
- [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)
|
- [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)
|
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#GbkToUtf8)
|
||||||
|
- [ToStdBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToStdBase64)
|
||||||
|
- [ToUrlBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToUrlBase64)
|
||||||
|
- [ToRawStdBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToRawStdBase64)
|
||||||
|
- [ToRawUrlBase64](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToRawUrlBase64)
|
||||||
|
|
||||||
|
|
||||||
### 3. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
### 3. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -131,17 +138,32 @@ import "github.com/duke-git/lancet/cryptor"
|
|||||||
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbEncrypt)
|
- [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)
|
- [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)
|
- [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)
|
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha1)
|
||||||
- [HmacSha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha256)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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 日期时间处理包,格式化日期,比较日期。
|
### 4. datetime 日期时间处理包,格式化日期,比较日期。
|
||||||
|
|
||||||
@@ -186,6 +208,11 @@ import "github.com/duke-git/lancet/datetime"
|
|||||||
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#BetweenSeconds)
|
- [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)
|
- [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)
|
- [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 包支持文件基本操作。
|
### 5. fileutil 包支持文件基本操作。
|
||||||
|
|
||||||
@@ -218,8 +245,10 @@ import "github.com/duke-git/lancet/fileutil"
|
|||||||
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Sha)
|
- [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)
|
- [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)
|
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteCsvFile)
|
||||||
|
- [WriteMapsToCsv](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteMapsToCsv)
|
||||||
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteStringToFile)
|
- [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)
|
- [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)
|
||||||
|
|
||||||
### 6. formatter 格式化器包含一些数据格式化处理方法。
|
### 6. formatter 格式化器包含一些数据格式化处理方法。
|
||||||
|
|
||||||
@@ -270,6 +299,10 @@ import "github.com/duke-git/lancet/mathutil"
|
|||||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToFloat)
|
- [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)
|
- [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)
|
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#TruncRound)
|
||||||
|
- [CeilToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#CeilToFloat)
|
||||||
|
- [CeilToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#CeilToString)
|
||||||
|
- [FloorToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#FloorToFloat)
|
||||||
|
- [FloorToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#FloorToString)
|
||||||
- [AngleToRadian](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#AngleToRadian)
|
- [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)
|
- [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)
|
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#PointDistance)
|
||||||
@@ -387,6 +420,7 @@ import "github.com/duke-git/lancet/slice"
|
|||||||
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Union)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
|
||||||
### 13. strutil 包含处理字符串的相关函数。
|
### 13. strutil 包含处理字符串的相关函数。
|
||||||
|
|
||||||
@@ -432,6 +466,8 @@ import "github.com/duke-git/lancet/strutil"
|
|||||||
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitAndTrim)
|
- [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)
|
- [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)
|
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveWhiteSpace)
|
||||||
|
- [SubInBetween](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SubInBetween)
|
||||||
|
- [HammingDistance](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HammingDistance)
|
||||||
|
|
||||||
### 14. system 包含 os, runtime, shell command 相关函数。
|
### 14. system 包含 os, runtime, shell command 相关函数。
|
||||||
|
|
||||||
@@ -492,6 +528,15 @@ import "github.com/duke-git/lancet/validator"
|
|||||||
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsGBK)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
|
||||||
## 如何贡献代码
|
## 如何贡献代码
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package convertor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -294,48 +295,6 @@ func DeepClone(src interface{}) interface{} {
|
|||||||
return result.Interface()
|
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.
|
// 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.
|
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
|
||||||
func CopyProperties(dst, src interface{}) error {
|
func CopyProperties(dst, src interface{}) error {
|
||||||
@@ -404,3 +363,99 @@ func GbkToUtf8(bs []byte) ([]byte, error) {
|
|||||||
b, err := io.ReadAll(r)
|
b, err := io.ReadAll(r)
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MapToStruct converts map to struct
|
||||||
|
func MapToStruct(m map[string]interface{}, structObj interface{}) error {
|
||||||
|
for k, v := range m {
|
||||||
|
err := setStructField(structObj, k, v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToStdBase64 convert data to standard base64 encoding.
|
||||||
|
func ToStdBase64(value interface{}) string {
|
||||||
|
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return base64.StdEncoding.EncodeToString(value.([]byte))
|
||||||
|
case string:
|
||||||
|
return base64.StdEncoding.EncodeToString([]byte(value.(string)))
|
||||||
|
case error:
|
||||||
|
return base64.StdEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||||
|
default:
|
||||||
|
marshal, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(marshal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToUrlBase64 convert data to URL base64 encoding.
|
||||||
|
func ToUrlBase64(value interface{}) string {
|
||||||
|
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return base64.URLEncoding.EncodeToString(value.([]byte))
|
||||||
|
case string:
|
||||||
|
return base64.URLEncoding.EncodeToString([]byte(value.(string)))
|
||||||
|
case error:
|
||||||
|
return base64.URLEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||||
|
default:
|
||||||
|
marshal, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return base64.URLEncoding.EncodeToString(marshal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRawStdBase64 convert data to raw standard base64 encoding.
|
||||||
|
func ToRawStdBase64(value interface{}) string {
|
||||||
|
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return base64.RawStdEncoding.EncodeToString(value.([]byte))
|
||||||
|
case string:
|
||||||
|
return base64.RawStdEncoding.EncodeToString([]byte(value.(string)))
|
||||||
|
case error:
|
||||||
|
return base64.RawStdEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||||
|
default:
|
||||||
|
marshal, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return base64.RawStdEncoding.EncodeToString(marshal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRawUrlBase64 convert data to raw URL base64 encoding.
|
||||||
|
func ToRawUrlBase64(value interface{}) string {
|
||||||
|
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return base64.RawURLEncoding.EncodeToString(value.([]byte))
|
||||||
|
case string:
|
||||||
|
return base64.RawURLEncoding.EncodeToString([]byte(value.(string)))
|
||||||
|
case error:
|
||||||
|
return base64.RawURLEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||||
|
default:
|
||||||
|
marshal, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return base64.RawURLEncoding.EncodeToString(marshal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
// Package convertor implements some functions to convert data.
|
// Package convertor implements some functions to convert data.
|
||||||
package convertor
|
package convertor
|
||||||
|
|
||||||
import "reflect"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
type cloner struct {
|
type cloner struct {
|
||||||
ptrs map[reflect.Type]map[uintptr]reflect.Value
|
ptrs map[reflect.Type]map[uintptr]reflect.Value
|
||||||
@@ -214,3 +217,70 @@ func (c *cloner) cloneStruct(v reflect.Value) reflect.Value {
|
|||||||
|
|
||||||
return clonedStruct
|
return clonedStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setStructField(structObj interface{}, fieldName string, fieldValue interface{}) error {
|
||||||
|
structVal := reflect.ValueOf(structObj).Elem()
|
||||||
|
|
||||||
|
fName := getFieldNameByJsonTag(structObj, fieldName)
|
||||||
|
if fName == "" {
|
||||||
|
return fmt.Errorf("Struct field json tag don't match map key : %s in obj", fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldVal := structVal.FieldByName(fName)
|
||||||
|
|
||||||
|
if !fieldVal.IsValid() {
|
||||||
|
return fmt.Errorf("No such field: %s in obj", fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fieldVal.CanSet() {
|
||||||
|
return fmt.Errorf("Cannot set %s field value", fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(fieldValue)
|
||||||
|
|
||||||
|
if fieldVal.Type() != val.Type() {
|
||||||
|
|
||||||
|
if val.CanConvert(fieldVal.Type()) {
|
||||||
|
fieldVal.Set(val.Convert(fieldVal.Type()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, ok := fieldValue.(map[string]interface{}); ok {
|
||||||
|
|
||||||
|
if fieldVal.Kind() == reflect.Struct {
|
||||||
|
return MapToStruct(m, fieldVal.Addr().Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldVal.Kind() == reflect.Ptr && fieldVal.Type().Elem().Kind() == reflect.Struct {
|
||||||
|
if fieldVal.IsNil() {
|
||||||
|
fieldVal.Set(reflect.New(fieldVal.Type().Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return MapToStruct(m, fieldVal.Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Map value type don't match struct field type")
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldVal.Set(val)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFieldNameByJsonTag(structObj interface{}, jsonTag string) string {
|
||||||
|
s := reflect.TypeOf(structObj).Elem()
|
||||||
|
|
||||||
|
for i := 0; i < s.NumField(); i++ {
|
||||||
|
field := s.Field(i)
|
||||||
|
tag := field.Tag
|
||||||
|
name := tag.Get("json")
|
||||||
|
|
||||||
|
if name == jsonTag {
|
||||||
|
return field.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
package convertor
|
package convertor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/internal"
|
"github.com/duke-git/lancet/internal"
|
||||||
"github.com/duke-git/lancet/validator"
|
"github.com/duke-git/lancet/validator"
|
||||||
@@ -363,3 +367,316 @@ func TestGbkToUtf8(t *testing.T) {
|
|||||||
assert.Equal(true, utf8.Valid(utf8Data))
|
assert.Equal(true, utf8.Valid(utf8Data))
|
||||||
assert.Equal("hello", string(utf8Data))
|
assert.Equal("hello", string(utf8Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMapToStruct(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestMapToStruct")
|
||||||
|
|
||||||
|
type Address struct {
|
||||||
|
Street string `json:"street"`
|
||||||
|
Number int `json:"number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Addr *Address `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"name": "Nothin",
|
||||||
|
"age": 28,
|
||||||
|
"phone": "123456789",
|
||||||
|
"address": map[string]interface{}{
|
||||||
|
"street": "test",
|
||||||
|
"number": 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var p Person
|
||||||
|
err := MapToStruct(m, &p)
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(m["name"], p.Name)
|
||||||
|
assert.Equal(m["age"], p.Age)
|
||||||
|
assert.Equal(m["phone"], p.Phone)
|
||||||
|
assert.Equal("test", p.Addr.Street)
|
||||||
|
assert.Equal(1, p.Addr.Number)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToStdBase64(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestToStdBase64")
|
||||||
|
|
||||||
|
r1 := ToStdBase64("abc")
|
||||||
|
d1, _ := base64.StdEncoding.DecodeString(r1)
|
||||||
|
assert.Equal("abc", string(d1))
|
||||||
|
|
||||||
|
r2 := ToStdBase64([]byte("abc"))
|
||||||
|
d2, _ := base64.StdEncoding.DecodeString(r2)
|
||||||
|
assert.Equal("abc", string(d2))
|
||||||
|
|
||||||
|
r3 := ToStdBase64(123)
|
||||||
|
d3, _ := base64.StdEncoding.DecodeString(r3)
|
||||||
|
assert.Equal("123", string(d3))
|
||||||
|
|
||||||
|
r4 := ToStdBase64(11.11)
|
||||||
|
d4, _ := base64.StdEncoding.DecodeString(r4)
|
||||||
|
assert.Equal("11.11", string(d4))
|
||||||
|
|
||||||
|
r5 := ToStdBase64(map[string]interface{}{"name": "duke", "quantity": 1})
|
||||||
|
d5, _ := base64.StdEncoding.DecodeString(r5)
|
||||||
|
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||||
|
|
||||||
|
r6 := ToStdBase64([]int64{7, 5, 9, 4, 23})
|
||||||
|
d6, _ := base64.StdEncoding.DecodeString(r6)
|
||||||
|
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||||
|
|
||||||
|
r7 := ToStdBase64([]string{"7", "5", "9", "4", "23"})
|
||||||
|
d7, _ := base64.StdEncoding.DecodeString(r7)
|
||||||
|
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||||
|
|
||||||
|
r8 := ToStdBase64(nil)
|
||||||
|
d8, _ := base64.StdEncoding.DecodeString(r8)
|
||||||
|
assert.Equal("", string(d8))
|
||||||
|
|
||||||
|
ch := make(chan int, 3)
|
||||||
|
ch <- 1
|
||||||
|
ch <- 2
|
||||||
|
r9 := ToStdBase64(ch)
|
||||||
|
d9, _ := base64.StdEncoding.DecodeString(r9)
|
||||||
|
assert.Equal("", string(d9))
|
||||||
|
|
||||||
|
r10 := ToStdBase64(io.EOF)
|
||||||
|
d10, _ := base64.StdEncoding.DecodeString(r10)
|
||||||
|
assert.Equal("EOF", string(d10))
|
||||||
|
|
||||||
|
r11 := ToStdBase64(errors.New("test"))
|
||||||
|
d11, _ := base64.StdEncoding.DecodeString(r11)
|
||||||
|
assert.Equal("test", string(d11))
|
||||||
|
|
||||||
|
typedNil := (*int)(nil)
|
||||||
|
r12 := ToStdBase64(typedNil)
|
||||||
|
d12, _ := base64.StdEncoding.DecodeString(r12)
|
||||||
|
assert.Equal("", string(d12))
|
||||||
|
|
||||||
|
type nilInterface interface {
|
||||||
|
}
|
||||||
|
var nI nilInterface = nil
|
||||||
|
d13, _ := base64.StdEncoding.DecodeString(ToStdBase64(nI))
|
||||||
|
assert.Equal("", string(d13))
|
||||||
|
|
||||||
|
var p unsafe.Pointer
|
||||||
|
d14, _ := base64.StdEncoding.DecodeString(ToStdBase64(p))
|
||||||
|
assert.Equal("", string(d14))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToUrlBase64(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestToUrlBase64")
|
||||||
|
|
||||||
|
r1 := ToUrlBase64("abc")
|
||||||
|
d1, _ := base64.URLEncoding.DecodeString(r1)
|
||||||
|
assert.Equal("abc", string(d1))
|
||||||
|
|
||||||
|
r2 := ToUrlBase64([]byte("abc"))
|
||||||
|
d2, _ := base64.URLEncoding.DecodeString(r2)
|
||||||
|
assert.Equal("abc", string(d2))
|
||||||
|
|
||||||
|
r3 := ToUrlBase64(123)
|
||||||
|
d3, _ := base64.URLEncoding.DecodeString(r3)
|
||||||
|
assert.Equal("123", string(d3))
|
||||||
|
|
||||||
|
r4 := ToUrlBase64(11.11)
|
||||||
|
d4, _ := base64.URLEncoding.DecodeString(r4)
|
||||||
|
assert.Equal("11.11", string(d4))
|
||||||
|
|
||||||
|
r5 := ToUrlBase64(map[string]interface{}{"name": "duke", "quantity": 1})
|
||||||
|
d5, _ := base64.URLEncoding.DecodeString(r5)
|
||||||
|
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||||
|
|
||||||
|
r6 := ToUrlBase64([]int64{7, 5, 9, 4, 23})
|
||||||
|
d6, _ := base64.URLEncoding.DecodeString(r6)
|
||||||
|
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||||
|
|
||||||
|
r7 := ToUrlBase64([]string{"7", "5", "9", "4", "23"})
|
||||||
|
d7, _ := base64.URLEncoding.DecodeString(r7)
|
||||||
|
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||||
|
|
||||||
|
r8 := ToUrlBase64(nil)
|
||||||
|
d8, _ := base64.URLEncoding.DecodeString(r8)
|
||||||
|
assert.Equal("", string(d8))
|
||||||
|
|
||||||
|
ch := make(chan int, 3)
|
||||||
|
ch <- 1
|
||||||
|
ch <- 2
|
||||||
|
r9 := ToUrlBase64(ch)
|
||||||
|
d9, _ := base64.URLEncoding.DecodeString(r9)
|
||||||
|
assert.Equal("", string(d9))
|
||||||
|
|
||||||
|
r10 := ToUrlBase64(io.EOF)
|
||||||
|
d10, _ := base64.URLEncoding.DecodeString(r10)
|
||||||
|
assert.Equal("EOF", string(d10))
|
||||||
|
|
||||||
|
r11 := ToUrlBase64(errors.New("test"))
|
||||||
|
d11, _ := base64.URLEncoding.DecodeString(r11)
|
||||||
|
assert.Equal("test", string(d11))
|
||||||
|
|
||||||
|
typedNil := (*int)(nil)
|
||||||
|
r12 := ToUrlBase64(typedNil)
|
||||||
|
d12, _ := base64.URLEncoding.DecodeString(r12)
|
||||||
|
assert.Equal("", string(d12))
|
||||||
|
|
||||||
|
type nilInterface interface {
|
||||||
|
}
|
||||||
|
var nI nilInterface = nil
|
||||||
|
d13, _ := base64.URLEncoding.DecodeString(ToUrlBase64(nI))
|
||||||
|
assert.Equal("", string(d13))
|
||||||
|
|
||||||
|
var p unsafe.Pointer
|
||||||
|
d14, _ := base64.URLEncoding.DecodeString(ToUrlBase64(p))
|
||||||
|
assert.Equal("", string(d14))
|
||||||
|
|
||||||
|
r15 := ToUrlBase64("4+3/4?=")
|
||||||
|
d15, _ := base64.URLEncoding.DecodeString(r15)
|
||||||
|
assert.Equal("4+3/4?=", string(d15))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToRawStdBase64(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestToRawStdBase64")
|
||||||
|
|
||||||
|
r1 := ToRawStdBase64("abc")
|
||||||
|
d1, _ := base64.RawStdEncoding.DecodeString(r1)
|
||||||
|
assert.Equal("abc", string(d1))
|
||||||
|
|
||||||
|
r2 := ToRawStdBase64([]byte("abc"))
|
||||||
|
d2, _ := base64.RawStdEncoding.DecodeString(r2)
|
||||||
|
assert.Equal("abc", string(d2))
|
||||||
|
|
||||||
|
r3 := ToRawStdBase64(123)
|
||||||
|
d3, _ := base64.RawStdEncoding.DecodeString(r3)
|
||||||
|
assert.Equal("123", string(d3))
|
||||||
|
|
||||||
|
r4 := ToRawStdBase64(11.11)
|
||||||
|
d4, _ := base64.RawStdEncoding.DecodeString(r4)
|
||||||
|
assert.Equal("11.11", string(d4))
|
||||||
|
|
||||||
|
r5 := ToRawStdBase64(map[string]interface{}{"name": "duke", "quantity": 1})
|
||||||
|
d5, _ := base64.RawStdEncoding.DecodeString(r5)
|
||||||
|
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||||
|
|
||||||
|
r6 := ToRawStdBase64([]int64{7, 5, 9, 4, 23})
|
||||||
|
d6, _ := base64.RawStdEncoding.DecodeString(r6)
|
||||||
|
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||||
|
|
||||||
|
r7 := ToRawStdBase64([]string{"7", "5", "9", "4", "23"})
|
||||||
|
d7, _ := base64.RawStdEncoding.DecodeString(r7)
|
||||||
|
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||||
|
|
||||||
|
r8 := ToRawStdBase64(nil)
|
||||||
|
d8, _ := base64.RawStdEncoding.DecodeString(r8)
|
||||||
|
assert.Equal("", string(d8))
|
||||||
|
|
||||||
|
ch := make(chan int, 3)
|
||||||
|
ch <- 1
|
||||||
|
ch <- 2
|
||||||
|
r9 := ToRawStdBase64(ch)
|
||||||
|
d9, _ := base64.RawStdEncoding.DecodeString(r9)
|
||||||
|
assert.Equal("", string(d9))
|
||||||
|
|
||||||
|
r10 := ToRawStdBase64(io.EOF)
|
||||||
|
d10, _ := base64.RawStdEncoding.DecodeString(r10)
|
||||||
|
assert.Equal("EOF", string(d10))
|
||||||
|
|
||||||
|
r11 := ToRawStdBase64(errors.New("test"))
|
||||||
|
d11, _ := base64.RawStdEncoding.DecodeString(r11)
|
||||||
|
assert.Equal("test", string(d11))
|
||||||
|
|
||||||
|
typedNil := (*int)(nil)
|
||||||
|
r12 := ToRawStdBase64(typedNil)
|
||||||
|
d12, _ := base64.RawStdEncoding.DecodeString(r12)
|
||||||
|
assert.Equal("", string(d12))
|
||||||
|
|
||||||
|
type nilInterface interface {
|
||||||
|
}
|
||||||
|
var nI nilInterface = nil
|
||||||
|
d13, _ := base64.RawStdEncoding.DecodeString(ToRawStdBase64(nI))
|
||||||
|
assert.Equal("", string(d13))
|
||||||
|
|
||||||
|
var p unsafe.Pointer
|
||||||
|
d14, _ := base64.RawStdEncoding.DecodeString(ToRawStdBase64(p))
|
||||||
|
assert.Equal("", string(d14))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToRawUrlBase64(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestToRawUrlBase64")
|
||||||
|
|
||||||
|
r1 := ToRawUrlBase64("abc")
|
||||||
|
d1, _ := base64.RawURLEncoding.DecodeString(r1)
|
||||||
|
assert.Equal("abc", string(d1))
|
||||||
|
|
||||||
|
r2 := ToRawUrlBase64([]byte("abc"))
|
||||||
|
d2, _ := base64.RawURLEncoding.DecodeString(r2)
|
||||||
|
assert.Equal("abc", string(d2))
|
||||||
|
|
||||||
|
r3 := ToRawUrlBase64(123)
|
||||||
|
d3, _ := base64.RawURLEncoding.DecodeString(r3)
|
||||||
|
assert.Equal("123", string(d3))
|
||||||
|
|
||||||
|
r4 := ToRawUrlBase64(11.11)
|
||||||
|
d4, _ := base64.RawURLEncoding.DecodeString(r4)
|
||||||
|
assert.Equal("11.11", string(d4))
|
||||||
|
|
||||||
|
r5 := ToRawUrlBase64(map[string]interface{}{"name": "duke", "quantity": 1})
|
||||||
|
d5, _ := base64.RawURLEncoding.DecodeString(r5)
|
||||||
|
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||||
|
|
||||||
|
r6 := ToRawUrlBase64([]int64{7, 5, 9, 4, 23})
|
||||||
|
d6, _ := base64.RawURLEncoding.DecodeString(r6)
|
||||||
|
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||||
|
|
||||||
|
r7 := ToRawUrlBase64([]string{"7", "5", "9", "4", "23"})
|
||||||
|
d7, _ := base64.RawURLEncoding.DecodeString(r7)
|
||||||
|
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||||
|
|
||||||
|
r8 := ToRawUrlBase64(nil)
|
||||||
|
d8, _ := base64.RawURLEncoding.DecodeString(r8)
|
||||||
|
assert.Equal("", string(d8))
|
||||||
|
|
||||||
|
ch := make(chan int, 3)
|
||||||
|
ch <- 1
|
||||||
|
ch <- 2
|
||||||
|
r9 := ToRawUrlBase64(ch)
|
||||||
|
d9, _ := base64.RawURLEncoding.DecodeString(r9)
|
||||||
|
assert.Equal("", string(d9))
|
||||||
|
|
||||||
|
r10 := ToRawUrlBase64(io.EOF)
|
||||||
|
d10, _ := base64.RawURLEncoding.DecodeString(r10)
|
||||||
|
assert.Equal("EOF", string(d10))
|
||||||
|
|
||||||
|
r11 := ToRawUrlBase64(errors.New("test"))
|
||||||
|
d11, _ := base64.RawURLEncoding.DecodeString(r11)
|
||||||
|
assert.Equal("test", string(d11))
|
||||||
|
|
||||||
|
typedNil := (*int)(nil)
|
||||||
|
r12 := ToRawUrlBase64(typedNil)
|
||||||
|
d12, _ := base64.RawURLEncoding.DecodeString(r12)
|
||||||
|
assert.Equal("", string(d12))
|
||||||
|
|
||||||
|
type nilInterface interface {
|
||||||
|
}
|
||||||
|
var nI nilInterface = nil
|
||||||
|
d13, _ := base64.RawURLEncoding.DecodeString(ToRawUrlBase64(nI))
|
||||||
|
assert.Equal("", string(d13))
|
||||||
|
|
||||||
|
var p unsafe.Pointer
|
||||||
|
d14, _ := base64.RawURLEncoding.DecodeString(ToRawUrlBase64(p))
|
||||||
|
assert.Equal("", string(d14))
|
||||||
|
|
||||||
|
r15 := ToRawUrlBase64("4+3/4?=")
|
||||||
|
d15, _ := base64.RawURLEncoding.DecodeString(r15)
|
||||||
|
assert.Equal("4+3/4?=", string(d15))
|
||||||
|
}
|
||||||
|
|||||||
188
cryptor/aes.go
188
cryptor/aes.go
@@ -1,188 +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 {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
}
|
||||||
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))
|
||||||
|
}
|
||||||
178
cryptor/des.go
178
cryptor/des.go
@@ -1,178 +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)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -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))
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
// 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"
|
||||||
@@ -18,14 +18,20 @@
|
|||||||
// "yyyy/mm"
|
// "yyyy/mm"
|
||||||
// "mm/dd"
|
// "mm/dd"
|
||||||
// "dd/mm/yy hh:mm:ss"
|
// "dd/mm/yy hh:mm:ss"
|
||||||
|
// "yyyymmdd"
|
||||||
|
// "mmddyy"
|
||||||
// "yyyy"
|
// "yyyy"
|
||||||
|
// "yy"
|
||||||
// "mm"
|
// "mm"
|
||||||
// "hh:mm:ss"
|
// "hh:mm:ss"
|
||||||
|
// "hh:mm"
|
||||||
// "mm:ss"
|
// "mm:ss"
|
||||||
|
|
||||||
package datetime
|
package datetime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -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",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,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
|
||||||
@@ -210,3 +241,83 @@ func DayOfYear(t time.Time) int {
|
|||||||
func IsWeekend(t time.Time) bool {
|
func IsWeekend(t time.Time) bool {
|
||||||
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
|
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()
|
||||||
|
}
|
||||||
|
|||||||
@@ -298,3 +298,38 @@ func TestIsWeekend(t *testing.T) {
|
|||||||
result2 := IsWeekend(date2)
|
result2 := IsWeekend(date2)
|
||||||
assert.Equal(false, result2)
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import (
|
|||||||
- [ToJson](#ToJson)
|
- [ToJson](#ToJson)
|
||||||
- [ToString](#ToString)
|
- [ToString](#ToString)
|
||||||
- [StructToMap](#StructToMap)
|
- [StructToMap](#StructToMap)
|
||||||
|
- [MapToStruct](#MapToStruct)
|
||||||
- [EncodeByte](#EncodeByte)
|
- [EncodeByte](#EncodeByte)
|
||||||
- [DecodeByte](#DecodeByte)
|
- [DecodeByte](#DecodeByte)
|
||||||
- [DeepClone](#DeepClone)
|
- [DeepClone](#DeepClone)
|
||||||
@@ -40,6 +41,10 @@ import (
|
|||||||
- [ToInterface](#ToInterface)
|
- [ToInterface](#ToInterface)
|
||||||
- [Utf8ToGbk](#Utf8ToGbk)
|
- [Utf8ToGbk](#Utf8ToGbk)
|
||||||
- [GbkToUtf8](#GbkToUtf8)
|
- [GbkToUtf8](#GbkToUtf8)
|
||||||
|
- [ToStdBase64](#ToStdBase64)
|
||||||
|
- [ToUrlBase64](#ToUrlBase64)
|
||||||
|
- [ToRawStdBase64](#ToRawStdBase64)
|
||||||
|
- [ToRawUrlBase64](#ToRawUrlBase64)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -356,7 +361,7 @@ 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>Converts struct to map, only convert exported field, struct field tag `json` should be set.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -389,6 +394,59 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="MapToStruct">MapToStruct</span>
|
||||||
|
|
||||||
|
<p>Converts map to struct, only convert exported field, struct field tag `json` should be set.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func MapToStruct(m map[string]interface{}, structObj interface{}) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Address struct {
|
||||||
|
Street string `json:"street"`
|
||||||
|
Number int `json:"number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Addr *Address `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"name": "Nothin",
|
||||||
|
"age": 28,
|
||||||
|
"phone": "123456789",
|
||||||
|
"address": map[string]interface{}{
|
||||||
|
"street": "test",
|
||||||
|
"number": 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var p Person
|
||||||
|
err := MapToStruct(m, &p)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("p.Addr.Street: %s", p.Addr.Street) //test
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="EncodeByte">EncodeByte</span>
|
### <span id="EncodeByte">EncodeByte</span>
|
||||||
|
|
||||||
<p>Encode data to byte slice.</p>
|
<p>Encode data to byte slice.</p>
|
||||||
@@ -686,4 +744,273 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
// hello
|
// hello
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToStdBase64">ToStdBase64</span>
|
||||||
|
|
||||||
|
<p>Convert a value to a string encoded in standard Base64. Error data of type "error" will also be encoded, and complex structures will be converted to a JSON-formatted string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToStdBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
afterEncode := convertor.ToStdBase64(nil)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
afterEncode = convertor.ToStdBase64("")
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToStdBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToStdBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToStdBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToStdBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToStdBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToStdBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToStdBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// aGVsbG8=
|
||||||
|
// aGVsbG8=
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
|
// MTIzLjQ1Ng==
|
||||||
|
// dHJ1ZQ==
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToUrlBase64">ToUrlBase64</span>
|
||||||
|
|
||||||
|
<p>Convert a value to a string encoded in url Base64. Error data of type "error" will also be encoded, and complex structures will be converted to a JSON-formatted string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToUrlBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
afterEncode := convertor.ToUrlBase64(nil)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToUrlBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToUrlBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToUrlBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToUrlBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToUrlBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToUrlBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToUrlBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// aGVsbG8=
|
||||||
|
// aGVsbG8=
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
|
// MTIzLjQ1Ng==
|
||||||
|
// dHJ1ZQ==
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToRawStdBase64">ToRawStdBase64</span>
|
||||||
|
|
||||||
|
<p>Convert a value to a string encoded in raw standard Base64. Error data of type "error" will also be encoded, and complex structures will be converted to a JSON-formatted string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToRawStdBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToRawStdBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToRawStdBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToRawStdBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToRawStdBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToRawStdBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// aGVsbG8
|
||||||
|
// aGVsbG8
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
|
// MTIzLjQ1Ng
|
||||||
|
// dHJ1ZQ
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToRawUrlBase64">ToRawUrlBase64</span>
|
||||||
|
|
||||||
|
<p> Convert a value to a string encoded in raw url Base64. Error data of type "error" will also be encoded, and complex structures will be converted to a JSON-formatted string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToRawUrlBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// aGVsbG8
|
||||||
|
// aGVsbG8
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
|
// MTIzLjQ1Ng
|
||||||
|
// dHJ1ZQ
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
```
|
```
|
||||||
@@ -33,6 +33,7 @@ import (
|
|||||||
- [ToJson](#ToJson)
|
- [ToJson](#ToJson)
|
||||||
- [ToString](#ToString)
|
- [ToString](#ToString)
|
||||||
- [StructToMap](#StructToMap)
|
- [StructToMap](#StructToMap)
|
||||||
|
- [MapToStruct](#MapToStruct)
|
||||||
- [EncodeByte](#EncodeByte)
|
- [EncodeByte](#EncodeByte)
|
||||||
- [DecodeByte](#DecodeByte)
|
- [DecodeByte](#DecodeByte)
|
||||||
- [DeepClone](#DeepClone)
|
- [DeepClone](#DeepClone)
|
||||||
@@ -40,6 +41,10 @@ import (
|
|||||||
- [ToInterface](#ToInterface)
|
- [ToInterface](#ToInterface)
|
||||||
- [Utf8ToGbk](#Utf8ToGbk)
|
- [Utf8ToGbk](#Utf8ToGbk)
|
||||||
- [GbkToUtf8](#GbkToUtf8)
|
- [GbkToUtf8](#GbkToUtf8)
|
||||||
|
- [ToStdBase64](#ToStdBase64)
|
||||||
|
- [ToUrlBase64](#ToUrlBase64)
|
||||||
|
- [ToRawStdBase64](#ToRawStdBase64)
|
||||||
|
- [ToRawUrlBase64](#ToRawUrlBase64)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -388,6 +393,59 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="MapToStruct">MapToStruct</span>
|
||||||
|
|
||||||
|
<p>将map转成struct,struct中导出字段需要设置json tag标记</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func MapToStruct(m map[string]interface{}, structObj interface{}) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Address struct {
|
||||||
|
Street string `json:"street"`
|
||||||
|
Number int `json:"number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Addr *Address `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"name": "Nothin",
|
||||||
|
"age": 28,
|
||||||
|
"phone": "123456789",
|
||||||
|
"address": map[string]interface{}{
|
||||||
|
"street": "test",
|
||||||
|
"number": 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var p Person
|
||||||
|
err := MapToStruct(m, &p)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("p.Addr.Street: %s", p.Addr.Street) //test
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="EncodeByte">EncodeByte</span>
|
### <span id="EncodeByte">EncodeByte</span>
|
||||||
|
|
||||||
<p>将data编码成字节切片</p>
|
<p>将data编码成字节切片</p>
|
||||||
@@ -686,4 +744,273 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
// hello
|
// hello
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToStdBase64">ToStdBase64</span>
|
||||||
|
|
||||||
|
<p>将值转换为StdBase64编码的字符串。error类型的数据也会把error的原因进行编码,复杂的结构会转为JSON格式的字符串</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToStdBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
afterEncode := convertor.ToStdBase64(nil)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
afterEncode = convertor.ToStdBase64("")
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToStdBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToStdBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToStdBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToStdBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToStdBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToStdBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToStdBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// aGVsbG8=
|
||||||
|
// aGVsbG8=
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
|
// MTIzLjQ1Ng==
|
||||||
|
// dHJ1ZQ==
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToUrlBase64">ToUrlBase64</span>
|
||||||
|
|
||||||
|
<p>值转换为 ToUrlBase64 编码的字符串。error 类型的数据也会把 error 的原因进行编码,复杂的结构会转为 JSON 格式的字符串</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToUrlBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
afterEncode := convertor.ToUrlBase64(nil)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToUrlBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToUrlBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToUrlBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToUrlBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToUrlBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToUrlBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToUrlBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// aGVsbG8=
|
||||||
|
// aGVsbG8=
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
|
// MTIzLjQ1Ng==
|
||||||
|
// dHJ1ZQ==
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToRawStdBase64">ToRawStdBase64</span>
|
||||||
|
|
||||||
|
<p>值转换为 ToRawStdBase64 编码的字符串。error 类型的数据也会把 error 的原因进行编码,复杂的结构会转为 JSON 格式的字符串</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToRawStdBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToRawStdBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToRawStdBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToRawStdBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToRawStdBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToRawStdBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// aGVsbG8
|
||||||
|
// aGVsbG8
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
|
// MTIzLjQ1Ng
|
||||||
|
// dHJ1ZQ
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToRawUrlBase64">ToRawUrlBase64</span>
|
||||||
|
|
||||||
|
<p>值转换为 ToRawUrlBase64 编码的字符串。error 类型的数据也会把 error 的原因进行编码,复杂的结构会转为 JSON 格式的字符串</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToRawUrlBase64(value any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
stringVal := "hello"
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(stringVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
byteSliceVal := []byte("hello")
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(byteSliceVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
intVal := 123
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(intVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
|
A string
|
||||||
|
B int
|
||||||
|
}{"hello", 3}}
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(mapVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
floatVal := 123.456
|
||||||
|
afterEncode = convertor.ToRawUrlBase64(floatVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
boolVal := true
|
||||||
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
errVal := errors.New("err")
|
||||||
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// aGVsbG8
|
||||||
|
// aGVsbG8
|
||||||
|
// MTIz
|
||||||
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
|
// MTIzLjQ1Ng
|
||||||
|
// dHJ1ZQ
|
||||||
|
// ZXJy
|
||||||
|
}
|
||||||
```
|
```
|
||||||
424
docs/cryptor.md
424
docs/cryptor.md
@@ -6,10 +6,8 @@ Package cryptor contains some functions for data encryption and decryption. Supp
|
|||||||
|
|
||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go](https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go)
|
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/des.go](https://github.com/duke-git/lancet/blob/v1/cryptor/des.go)
|
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go](https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go)
|
- [https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go](https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go)
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go)
|
- [https://github.com/duke-git/lancet/blob/v1/cryptor/crypto.go](https://github.com/duke-git/lancet/blob/v1/cryptor/crypto.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -46,17 +44,30 @@ import (
|
|||||||
- [DesOfbEncrypt](#DesOfbEncrypt)
|
- [DesOfbEncrypt](#DesOfbEncrypt)
|
||||||
- [DesOfbDecrypt](#DesOfbDecrypt)
|
- [DesOfbDecrypt](#DesOfbDecrypt)
|
||||||
- [HmacMd5](#HmacMd5)
|
- [HmacMd5](#HmacMd5)
|
||||||
|
- [HmacMd5WithBase64](#HmacMd5WithBase64)
|
||||||
- [HmacSha1](#HmacSha1)
|
- [HmacSha1](#HmacSha1)
|
||||||
|
- [HmacSha1WithBase64](#HmacSha1WithBase64)
|
||||||
- [HmacSha256](#HmacSha256)
|
- [HmacSha256](#HmacSha256)
|
||||||
|
- [HmacSha256WithBase64](#HmacSha256WithBase64)
|
||||||
- [HmacSha512](#HmacSha512)
|
- [HmacSha512](#HmacSha512)
|
||||||
|
- [HmacSha512WithBase64](#HmacSha512WithBase64)
|
||||||
- [Md5String](#Md5String)
|
- [Md5String](#Md5String)
|
||||||
|
- [Md5StringWithBase64](#Md5StringWithBase64)
|
||||||
|
- [Md5Byte](#Md5Byte)
|
||||||
|
- [Md5ByteWithBase64](#Md5ByteWithBase64)
|
||||||
- [Md5File](#Md5File)
|
- [Md5File](#Md5File)
|
||||||
- [Sha1](#Sha1)
|
- [Sha1](#Sha1)
|
||||||
|
- [Sha1WithBase64](#Sha1WithBase64)
|
||||||
- [Sha256](#Sha256)
|
- [Sha256](#Sha256)
|
||||||
|
- [Sha256WithBase64](#Sha256WithBase64)
|
||||||
- [Sha512](#Sha512)
|
- [Sha512](#Sha512)
|
||||||
|
- [Sha512WithBase64](#Sha512WithBase64)
|
||||||
- [GenerateRsaKey](#GenerateRsaKey)
|
- [GenerateRsaKey](#GenerateRsaKey)
|
||||||
- [RsaEncrypt](#RsaEncrypt)
|
- [RsaEncrypt](#RsaEncrypt)
|
||||||
- [RsaDecrypt](#RsaDecrypt)
|
- [RsaDecrypt](#RsaDecrypt)
|
||||||
|
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
|
||||||
|
- [RsaEncryptOAEP](#RsaEncryptOAEP)
|
||||||
|
- [RsaDecryptOAEP](#RsaDecryptOAEP)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -664,6 +675,32 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="HmacMd5WithBase64">HmacMd5WithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the hmac hash of string use md5 with base64.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacMd5WithBase64(data, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := cryptor.HmacMd5WithBase64("hello", "12345"))
|
||||||
|
fmt.Println(s) //6DQwbquJLYclJdSRinpjmg==
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="HmacSha1">HmacSha1</span>
|
### <span id="HmacSha1">HmacSha1</span>
|
||||||
|
|
||||||
<p>Get the sha1 hmac hash of string.</p>
|
<p>Get the sha1 hmac hash of string.</p>
|
||||||
@@ -690,6 +727,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="HmacSha1WithBase64">HmacSha1WithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the hmac hash of string use sha1 with base64.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacSha1WithBase64(str, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
|
||||||
|
hms := cryptor.HmacSha1WithBase64(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="HmacSha256">HmacSha256</span>
|
### <span id="HmacSha256">HmacSha256</span>
|
||||||
|
|
||||||
<p>Get the sha256 hmac hash of string</p>
|
<p>Get the sha256 hmac hash of string</p>
|
||||||
@@ -716,6 +785,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="HmacSha256WithBase64">HmacSha256WithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the hmac hash of string use sha256 with base64.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacSha256WithBase64(str, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
|
||||||
|
hms := cryptor.HmacSha256WithBase64(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="HmacSha512">HmacSha512</span>
|
### <span id="HmacSha512">HmacSha512</span>
|
||||||
|
|
||||||
<p>Get the sha512 hmac hash of string.</p>
|
<p>Get the sha512 hmac hash of string.</p>
|
||||||
@@ -742,6 +843,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="HmacSha512WithBase64">HmacSha512WithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the hmac hash of string use sha512 with base64.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacSha512WithBase64(str, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
|
||||||
|
hms := cryptor.HmacSha512WithBase64(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Md5String">Md5String</span>
|
### <span id="Md5String">Md5String</span>
|
||||||
|
|
||||||
<p>Get the md5 value of string.</p>
|
<p>Get the md5 value of string.</p>
|
||||||
@@ -768,6 +901,93 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Md5StringWithBase64">Md5StringWithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the md5 value of string with base64.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Md5StringWithBase64(s string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
md5Str := cryptor.Md5StringWithBase64("hello")
|
||||||
|
fmt.Println(md5Str)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// XUFAKrxLKna5cZ2REBfFkg==
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Md5Byte">Md5Byte</span>
|
||||||
|
|
||||||
|
<p>Return the md5 string of byte slice.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Md5Byte(data []byte) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
md5Str := cryptor.Md5Byte([]byte{'a'})
|
||||||
|
fmt.Println(md5Str)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0cc175b9c0f1b6a831c399e269772661
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Md5ByteWithBase64">Md5ByteWithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the md5 string of byte slice with base64.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Md5ByteWithBase64(data []byte) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
md5Str := cryptor.Md5ByteWithBase64([]byte("hello"))
|
||||||
|
fmt.Println(md5Str)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// XUFAKrxLKna5cZ2REBfFkg==
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Md5File">Md5File</span>
|
### <span id="Md5File">Md5File</span>
|
||||||
|
|
||||||
<p>Get the md5 value of file.</p>
|
<p>Get the md5 value of file.</p>
|
||||||
@@ -820,6 +1040,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Sha1WithBase64">Sha1WithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the sha1 value (SHA-1 hash algorithm) of base64 string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha1WithBase64(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := cryptor.Sha1WithBase64("hello")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Sha256">Sha256</span>
|
### <span id="Sha256">Sha256</span>
|
||||||
|
|
||||||
<p>Get the sha256 value of string.</p>
|
<p>Get the sha256 value of string.</p>
|
||||||
@@ -846,6 +1095,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Sha256WithBase64">Sha256WithBase64</span>
|
||||||
|
|
||||||
|
<p>Return the sha256 value (SHA256 hash algorithm) of base64 string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha256WithBase64(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := cryptor.Sha256WithBase64("hello")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Sha512">Sha512</span>
|
### <span id="Sha512">Sha512</span>
|
||||||
|
|
||||||
<p>Get the sha512 value of string.</p>
|
<p>Get the sha512 value of string.</p>
|
||||||
@@ -872,6 +1150,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Sha512WithBase64">Sha512WithBase64</span>
|
||||||
|
|
||||||
|
<p>Get the sha512 value of string with base64.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha512WithBase64(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := cryptor.Sha512WithBase64("hello")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="GenerateRsaKey">GenerateRsaKey</span>
|
### <span id="GenerateRsaKey">GenerateRsaKey</span>
|
||||||
|
|
||||||
<p>Create the rsa public and private key file in current directory.</p>
|
<p>Create the rsa public and private key file in current directory.</p>
|
||||||
@@ -967,3 +1274,114 @@ func main() {
|
|||||||
fmt.Println(string(decrypted)) //hello world
|
fmt.Println(string(decrypted)) //hello world
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="GenerateRsaKeyPair">GenerateRsaKeyPair</span>
|
||||||
|
|
||||||
|
<p>Creates rsa private and public key.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pri, pub := cryptor.GenerateRsaKeyPair(1024)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RsaEncryptOAEP">RsaEncryptOAEP</span>
|
||||||
|
|
||||||
|
<p>Encrypts the given data with RSA-OAEP.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pri, pub := cryptor.GenerateRsaKeyPair(1024)
|
||||||
|
|
||||||
|
data := []byte("hello world")
|
||||||
|
label := []byte("123456")
|
||||||
|
|
||||||
|
encrypted, err := cryptor.RsaEncryptOAEP(data, label, *pub)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := cryptor.RsaDecryptOAEP([]byte(encrypted), label, *pri)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(decrypted))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RsaDecryptOAEP">RsaDecryptOAEP</span>
|
||||||
|
|
||||||
|
<p>Decrypts the data with RSA-OAEP.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pri, pub := cryptor.GenerateRsaKeyPair(1024)
|
||||||
|
|
||||||
|
data := []byte("hello world")
|
||||||
|
label := []byte("123456")
|
||||||
|
|
||||||
|
encrypted, err := cryptor.RsaEncryptOAEP(data, label, *pub)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := cryptor.RsaDecryptOAEP([]byte(encrypted), label, *pri)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(decrypted))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -6,10 +6,8 @@ cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 ba
|
|||||||
|
|
||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go](https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go)
|
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/des.go](https://github.com/duke-git/lancet/blob/v1/cryptor/des.go)
|
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go](https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go)
|
- [https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go](https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go)
|
||||||
- [https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go)
|
- [https://github.com/duke-git/lancet/blob/v1/cryptor/crypto.go](https://github.com/duke-git/lancet/blob/v1/cryptor/crypto.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -47,16 +45,28 @@ import (
|
|||||||
- [DesOfbDecrypt](#DesOfbDecrypt)
|
- [DesOfbDecrypt](#DesOfbDecrypt)
|
||||||
- [HmacMd5](#HmacMd5)
|
- [HmacMd5](#HmacMd5)
|
||||||
- [HmacSha1](#HmacSha1)
|
- [HmacSha1](#HmacSha1)
|
||||||
|
- [HmacSha1WithBase64](#HmacSha1WithBase64)
|
||||||
- [HmacSha256](#HmacSha256)
|
- [HmacSha256](#HmacSha256)
|
||||||
|
- [HmacSha256WithBase64](#HmacSha256WithBase64)
|
||||||
- [HmacSha512](#HmacSha512)
|
- [HmacSha512](#HmacSha512)
|
||||||
|
- [HmacSha512WithBase64](#HmacSha512WithBase64)
|
||||||
- [Md5String](#Md5String)
|
- [Md5String](#Md5String)
|
||||||
|
- [Md5StringWithBase64](#Md5StringWithBase64)
|
||||||
|
- [Md5Byte](#Md5Byte)
|
||||||
|
- [Md5ByteWithBase64](#Md5ByteWithBase64)
|
||||||
- [Md5File](#Md5File)
|
- [Md5File](#Md5File)
|
||||||
- [Sha1](#Sha1)
|
- [Sha1](#Sha1)
|
||||||
|
- [Sha1WithBase64](#Sha1WithBase64)
|
||||||
- [Sha256](#Sha256)
|
- [Sha256](#Sha256)
|
||||||
|
- [Sha256WithBase64](#Sha256WithBase64)
|
||||||
- [Sha512](#Sha512)
|
- [Sha512](#Sha512)
|
||||||
|
- [Sha512WithBase64](#Sha512WithBase64)
|
||||||
- [GenerateRsaKey](#GenerateRsaKey)
|
- [GenerateRsaKey](#GenerateRsaKey)
|
||||||
- [RsaEncrypt](#RsaEncrypt)
|
- [RsaEncrypt](#RsaEncrypt)
|
||||||
- [RsaDecrypt](#RsaDecrypt)
|
- [RsaDecrypt](#RsaDecrypt)
|
||||||
|
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
|
||||||
|
- [RsaEncryptOAEP](#RsaEncryptOAEP)
|
||||||
|
- [RsaDecryptOAEP](#RsaDecryptOAEP)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -663,6 +673,32 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="HmacMd5WithBase64">HmacMd5WithBase64</span>
|
||||||
|
|
||||||
|
<p>获取字符串md5 hmac base64值.</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacMd5WithBase64(data, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := cryptor.HmacMd5WithBase64("hello", "12345"))
|
||||||
|
fmt.Println(s) //6DQwbquJLYclJdSRinpjmg==
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="HmacSha1">HmacSha1</span>
|
### <span id="HmacSha1">HmacSha1</span>
|
||||||
|
|
||||||
<p>获取字符串sha1 hmac值</p>
|
<p>获取字符串sha1 hmac值</p>
|
||||||
@@ -689,17 +725,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="HmacSha256">HmacSha256</span>
|
### <span id="HmacSha1WithBase64">HmacSha1WithBase64</span>
|
||||||
|
|
||||||
<p>获取字符串sha256 hmac值</p>
|
<p>获取字符串的sha1 base64值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func HmacSha256(data, key string) string
|
func HmacSha1WithBase64(str, key string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>实例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -710,22 +746,92 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := cryptor.HmacSha256("hello world", "12345"))
|
str := "hello"
|
||||||
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
|
key := "12345"
|
||||||
|
|
||||||
|
hms := cryptor.HmacSha1WithBase64(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="HmacSha256">HmacSha256</span>
|
||||||
|
|
||||||
|
<p>获取字符串sha256 hmac值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacSha256(str, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
|
||||||
|
hms := cryptor.HmacSha256(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="HmacSha256WithBase64">HmacSha256WithBase64</span>
|
||||||
|
|
||||||
|
<p>获取字符串sha256 hmac base64值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacSha256WithBase64(str, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
|
||||||
|
hms := cryptor.HmacSha256WithBase64(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="HmacSha512">HmacSha512</span>
|
### <span id="HmacSha512">HmacSha512</span>
|
||||||
|
|
||||||
<p>获取字符串sha512 hmac值</p>
|
<p>获取字符串sha512 hmac值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func HmacSha512(data, key string) string
|
func HmacSha512(str, key string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -736,23 +842,60 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := cryptor.HmacSha512("hello world", "12345"))
|
str := "hello"
|
||||||
fmt.Println(s)
|
key := "12345"
|
||||||
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
|
|
||||||
|
hms := cryptor.HmacSha512(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="HmacSha512WithBase64">HmacSha512WithBase64</span>
|
||||||
|
|
||||||
|
<p>获取字符串sha512 hmac base64值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HmacSha512WithBase64(str, key string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "hello"
|
||||||
|
key := "12345"
|
||||||
|
|
||||||
|
hms := cryptor.HmacSha512WithBase64(str, key)
|
||||||
|
fmt.Println(hms)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="Md5String">Md5String</span>
|
### <span id="Md5String">Md5String</span>
|
||||||
|
|
||||||
<p>获取字符串md5值</p>
|
<p>获取字符串md5值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Md5String(s string) string
|
func Md5String(str string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -763,14 +906,106 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := cryptor.Md5String("hello"))
|
str := "hello"
|
||||||
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
|
|
||||||
|
md5Str := cryptor.Md5String(str)
|
||||||
|
fmt.Println(md5Str)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 5d41402abc4b2a76b9719d911017c592
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Md5StringWithBase64">Md5StringWithBase64</span>
|
||||||
|
|
||||||
|
<p>获取字符串md5 base64值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Md5StringWithBase64(s string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
md5Str := cryptor.Md5StringWithBase64("hello")
|
||||||
|
fmt.Println(md5Str)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// XUFAKrxLKna5cZ2REBfFkg==
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Md5Byte">Md5Byte</span>
|
||||||
|
|
||||||
|
<p>获取byte slice的md5值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Md5Byte(data []byte) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
md5Str := cryptor.Md5Byte([]byte{'a'})
|
||||||
|
fmt.Println(md5Str)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0cc175b9c0f1b6a831c399e269772661
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Md5ByteWithBase64">Md5ByteWithBase64</span>
|
||||||
|
|
||||||
|
<p>获取byte slice的md5 base64值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Md5ByteWithBase64(data []byte) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
md5Str := cryptor.Md5ByteWithBase64([]byte("hello"))
|
||||||
|
fmt.Println(md5Str)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// XUFAKrxLKna5cZ2REBfFkg==
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="Md5File">Md5File</span>
|
### <span id="Md5File">Md5File</span>
|
||||||
|
|
||||||
<p>获取文件md5值.</p>
|
<p>获取文件md5值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -778,7 +1013,7 @@ func main() {
|
|||||||
func Md5File(filepath string) (string, error)
|
func Md5File(filepath string) (string, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -796,15 +1031,15 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Sha1">Sha1</span>
|
### <span id="Sha1">Sha1</span>
|
||||||
|
|
||||||
<p>获取字符串sha1值</p>
|
<p>获取字符串sha1值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Sha1(data string) string
|
func Sha1(str string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -815,22 +1050,56 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := cryptor.Sha1("hello world"))
|
str := "hello"
|
||||||
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
|
|
||||||
|
result := cryptor.Sha1(str)
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Sha1WithBase64">Sha1WithBase64</span>
|
||||||
|
|
||||||
|
<p>获取字符串sha1 base64值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha1WithBase64(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := cryptor.Sha1WithBase64("hello")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="Sha256">Sha256</span>
|
### <span id="Sha256">Sha256</span>
|
||||||
|
|
||||||
<p>获取字符串sha256值</p>
|
<p>获取字符串sha256值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Sha256(data string) string
|
func Sha256(str string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -841,22 +1110,56 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := cryptor.Sha256("hello world"))
|
str := "hello"
|
||||||
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
|
||||||
|
result := cryptor.Sha256(str)
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Sha256WithBase64">Sha256WithBase64</span>
|
||||||
|
|
||||||
|
<p>获取字符串sha256 base64值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha256WithBase64(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := cryptor.Sha256WithBase64("hello")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="Sha512">Sha512</span>
|
### <span id="Sha512">Sha512</span>
|
||||||
|
|
||||||
<p>获取字符串sha512值</p>
|
<p>获取字符串sha512值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Sha512(data string) string
|
func Sha512(str string) string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>列子:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -867,8 +1170,42 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
s := cryptor.Sha512("hello world"))
|
str := "hello"
|
||||||
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
|
|
||||||
|
result := cryptor.Sha512(str)
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Sha512WithBase64">Sha512WithBase64</span>
|
||||||
|
|
||||||
|
<p>获取字符串sha512 base64值。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Sha512WithBase64(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := cryptor.Sha512WithBase64("hello")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -958,10 +1295,121 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data := []byte("hello world")
|
data := []byte("hello world")
|
||||||
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
|
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
|
||||||
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
|
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
|
||||||
fmt.Println(string(decrypted)) //hello world
|
fmt.Println(string(decrypted)) //hello world
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="GenerateRsaKeyPair">GenerateRsaKeyPair</span>
|
||||||
|
|
||||||
|
<p>创建rsa公钥私钥和key。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pri, pub := cryptor.GenerateRsaKeyPair(1024)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RsaEncryptOAEP">RsaEncryptOAEP</span>
|
||||||
|
|
||||||
|
<p>rsa OAEP加密。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pri, pub := cryptor.GenerateRsaKeyPair(1024)
|
||||||
|
|
||||||
|
data := []byte("hello world")
|
||||||
|
label := []byte("123456")
|
||||||
|
|
||||||
|
encrypted, err := cryptor.RsaEncryptOAEP(data, label, *pub)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := cryptor.RsaDecryptOAEP([]byte(encrypted), label, *pri)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(decrypted))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RsaDecryptOAEP">RsaDecryptOAEP</span>
|
||||||
|
|
||||||
|
<p>rsa OAEP解密。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/cryptor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pri, pub := cryptor.GenerateRsaKeyPair(1024)
|
||||||
|
|
||||||
|
data := []byte("hello world")
|
||||||
|
label := []byte("123456")
|
||||||
|
|
||||||
|
encrypted, err := cryptor.RsaEncryptOAEP(data, label, *pub)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := cryptor.RsaDecryptOAEP([]byte(encrypted), label, *pri)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(decrypted))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
209
docs/datetime.md
209
docs/datetime.md
@@ -57,6 +57,11 @@ import (
|
|||||||
- [BetweenSeconds](#BetweenSeconds)
|
- [BetweenSeconds](#BetweenSeconds)
|
||||||
- [DayOfYear](#DayOfYear)
|
- [DayOfYear](#DayOfYear)
|
||||||
- [IsWeekend](#IsWeekend)
|
- [IsWeekend](#IsWeekend)
|
||||||
|
- [NowDateOrTime](#NowDateOrTime)
|
||||||
|
- [Timestamp](#Timestamp)
|
||||||
|
- [TimestampMilli](#TimestampMilli)
|
||||||
|
- [TimestampMicro](#TimestampMicro)
|
||||||
|
- [TimestampNano](#TimestampNano)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -64,7 +69,7 @@ import (
|
|||||||
|
|
||||||
## Note:
|
## Note:
|
||||||
|
|
||||||
1. 'format' string param in func FormatTimeToStr and FormatStrToTime function should be one of flows:
|
1. In below functions, the `format` string param should be one of flows value (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
|
||||||
@@ -75,14 +80,18 @@ import (
|
|||||||
- 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
|
||||||
|
- yyyymmdd
|
||||||
|
- mmddyy
|
||||||
- yyyy
|
- yyyy
|
||||||
|
- yy
|
||||||
- mm
|
- mm
|
||||||
- hh:mm:ss
|
- hh:mm:ss
|
||||||
|
- hh:mm
|
||||||
- mm:ss
|
- mm:ss
|
||||||
|
|
||||||
### <span id="AddDay">AddDay</span>
|
### <span id="AddDay">AddDay</span>
|
||||||
@@ -1036,7 +1045,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="DayOfYear">DayOfYear</span>
|
### <span id="DayOfYear">DayOfYear</span>
|
||||||
|
|
||||||
<p>Returns which day of the year the parameter date `t` is.</p>
|
<p>Returns which day of the year the parameter date `t` is.</p>
|
||||||
@@ -1157,3 +1165,198 @@ func main() {
|
|||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsWeekend">IsWeekend</span>
|
||||||
|
|
||||||
|
<p>Checks if passed time is weekend or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsWeekend(t time.Time) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date1 := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||||
|
date2 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||||
|
date3 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||||
|
|
||||||
|
result1 := datetime.IsWeekend(date1)
|
||||||
|
result2 := datetime.IsWeekend(date2)
|
||||||
|
result3 := datetime.IsWeekend(date3)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="NowDateOrTime">NowDateOrTime</span>
|
||||||
|
|
||||||
|
<p>Return current datetime with specific format and timezone.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NowDateOrTime(format string, timezone ...string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
|
||||||
|
|
||||||
|
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2023-07-26 15:01:30
|
||||||
|
// 2023-07-26 02:01:30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Timestamp">Timestamp</span>
|
||||||
|
|
||||||
|
<p>Return current second timestamp.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Timestamp(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.Timestamp()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="TimestampMilli">TimestampMilli</span>
|
||||||
|
|
||||||
|
<p>Return current mill second timestamp.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TimestampMilli(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.TimestampMilli()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051331
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="TimestampMicro">TimestampMicro</span>
|
||||||
|
|
||||||
|
<p>Return current micro second timestamp.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TimestampMicro(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.TimestampMicro()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051331784
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="TimestampNano">TimestampNano</span>
|
||||||
|
|
||||||
|
<p>Return current nano second timestamp.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TimestampNano(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.TimestampNano()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051331788000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -57,7 +57,11 @@ import (
|
|||||||
- [BetweenSeconds](#BetweenSeconds)
|
- [BetweenSeconds](#BetweenSeconds)
|
||||||
- [DayOfYear](#DayOfYear)
|
- [DayOfYear](#DayOfYear)
|
||||||
- [IsWeekend](#IsWeekend)
|
- [IsWeekend](#IsWeekend)
|
||||||
|
- [NowDateOrTime](#NowDateOrTime)
|
||||||
|
- [Timestamp](#Timestamp)
|
||||||
|
- [TimestampMilli](#TimestampMilli)
|
||||||
|
- [TimestampMicro](#TimestampMicro)
|
||||||
|
- [TimestampNano](#TimestampNano)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -65,7 +69,7 @@ import (
|
|||||||
|
|
||||||
## 注:
|
## 注:
|
||||||
|
|
||||||
1. 方法 FormatTimeToStr 和 FormatStrToTime 中的 format 参数值需要传以下类型之一:
|
1. 函数中`format`参数值需要传以下值之一 (忽略大小写):
|
||||||
|
|
||||||
- yyyy-mm-dd hh:mm:ss
|
- yyyy-mm-dd hh:mm:ss
|
||||||
- yyyy-mm-dd hh:mm
|
- yyyy-mm-dd hh:mm
|
||||||
@@ -76,14 +80,18 @@ import (
|
|||||||
- 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
|
||||||
|
- yyyymmdd
|
||||||
|
- mmddyy
|
||||||
- yyyy
|
- yyyy
|
||||||
|
- yy
|
||||||
- mm
|
- mm
|
||||||
- hh:mm:ss
|
- hh:mm:ss
|
||||||
|
- hh:mm
|
||||||
- mm:ss
|
- mm:ss
|
||||||
|
|
||||||
### <span id="AddDay">AddDay</span>
|
### <span id="AddDay">AddDay</span>
|
||||||
@@ -1077,3 +1085,198 @@ func main() {
|
|||||||
// 0
|
// 0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsWeekend">IsWeekend</span>
|
||||||
|
|
||||||
|
<p>判断日期是否是周末。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsWeekend(t time.Time) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date1 := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||||
|
date2 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||||
|
date3 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||||
|
|
||||||
|
result1 := datetime.IsWeekend(date1)
|
||||||
|
result2 := datetime.IsWeekend(date2)
|
||||||
|
result3 := datetime.IsWeekend(date3)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="NowDateOrTime">NowDateOrTime</span>
|
||||||
|
|
||||||
|
<p>根据指定的格式和时区返回当前时间字符串。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NowDateOrTime(format string, timezone ...string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
|
||||||
|
|
||||||
|
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2023-07-26 15:01:30
|
||||||
|
// 2023-07-26 02:01:30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Timestamp">Timestamp</span>
|
||||||
|
|
||||||
|
<p>返回当前秒级时间戳。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Timestamp(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.Timestamp()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="TimestampMilli">TimestampMilli</span>
|
||||||
|
|
||||||
|
<p>返回当前毫秒级时间戳。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TimestampMilli(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.TimestampMilli()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051331
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="TimestampMicro">TimestampMicro</span>
|
||||||
|
|
||||||
|
<p>返回当前微秒级时间戳。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TimestampMicro(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.TimestampMicro()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051331784
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="TimestampNano">TimestampNano</span>
|
||||||
|
|
||||||
|
<p>返回当前纳秒级时间戳。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TimestampNano(timezone ...string) int64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>实例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts := datetime.TimestampNano()
|
||||||
|
|
||||||
|
fmt.Println(ts)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1690363051331788000
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -45,8 +45,10 @@ import (
|
|||||||
- [Sha](#Sha)
|
- [Sha](#Sha)
|
||||||
- [ReadCsvFile](#ReadCsvFile)
|
- [ReadCsvFile](#ReadCsvFile)
|
||||||
- [WriteCsvFile](#WriteCsvFile)
|
- [WriteCsvFile](#WriteCsvFile)
|
||||||
|
- [WriteMapsToCsv](#WriteMapsToCsv)
|
||||||
- [WriteStringToFile](#WriteStringToFile)
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
- [WriteBytesToFile](#WriteBytesToFile)
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
|
- [ReadFile](#ReadFile)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -693,6 +695,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="WriteCsvFile">WriteCsvFile</span>
|
### <span id="WriteCsvFile">WriteCsvFile</span>
|
||||||
|
|
||||||
<p>Write content to target csv file.</p>
|
<p>Write content to target csv file.</p>
|
||||||
@@ -730,6 +733,60 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="WriteMapsToCsv">WriteMapsToCsv</span>
|
||||||
|
|
||||||
|
<p>write slice of map to csv file.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
// filepath: path of the CSV file.
|
||||||
|
// records: slice of maps to be written. the value of map should be basic type. The maps will be sorted by key in alphabeta order, then be written into csv file.
|
||||||
|
// appendToExistingFile: If true, data will be appended to the file if it exists.
|
||||||
|
// delimiter: Delimiter to use in the CSV file.
|
||||||
|
// headers: order of the csv column headers, needs to be consistent with the key of the map.
|
||||||
|
func WriteMapsToCsv(filepath string, records []map[string]interface{}, appendToExistingFile bool, delimiter rune, headers ...[]string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fpath := "./test.csv"
|
||||||
|
fileutil.CreateFile(fpath)
|
||||||
|
|
||||||
|
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
records := []map[string]interface{}{
|
||||||
|
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||||
|
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := []string{"Name", "Age", "Gender"}
|
||||||
|
err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||||
|
|
||||||
<p>Writes bytes to target file.</p>
|
<p>Writes bytes to target file.</p>
|
||||||
@@ -827,3 +884,41 @@ func main() {
|
|||||||
// hello
|
// 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
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -45,8 +45,10 @@ import (
|
|||||||
- [Sha](#Sha)
|
- [Sha](#Sha)
|
||||||
- [ReadCsvFile](#ReadCsvFile)
|
- [ReadCsvFile](#ReadCsvFile)
|
||||||
- [WriteCsvFile](#WriteCsvFile)
|
- [WriteCsvFile](#WriteCsvFile)
|
||||||
|
- [WriteMapsToCsv](#WriteMapsToCsv)
|
||||||
- [WriteStringToFile](#WriteStringToFile)
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
- [WriteBytesToFile](#WriteBytesToFile)
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
|
- [ReadFile](#ReadFile)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -730,6 +732,59 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="WriteMapsToCsv">WriteMapsToCsv</span>
|
||||||
|
|
||||||
|
<p>将map切片写入csv文件中。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
// filepath: CSV文件路径。
|
||||||
|
// records: 写入文件的map切片。map值必须为基本类型。会以map键的字母顺序写入。
|
||||||
|
// appendToExistingFile: 是否为追加写模式。
|
||||||
|
// delimiter: CSV文件分割符。
|
||||||
|
// headers: CSV文件表头顺序(需要与map key保持一致),不指定时按字母排序。
|
||||||
|
func WriteMapsToCsv(filepath string, records []map[string]interface{}, appendToExistingFile bool, delimiter rune, headers ...[]string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fpath := "./test.csv"
|
||||||
|
fileutil.CreateFile(fpath)
|
||||||
|
|
||||||
|
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
records := []map[string]interface{}{
|
||||||
|
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||||
|
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := []string{"Name", "Age", "Gender"}
|
||||||
|
err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
|
||||||
|
|
||||||
|
fmt.Println(content)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||||
|
|
||||||
<p>将bytes写入文件。</p>
|
<p>将bytes写入文件。</p>
|
||||||
@@ -827,3 +882,41 @@ func main() {
|
|||||||
// hello
|
// 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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
148
docs/mathutil.md
148
docs/mathutil.md
@@ -29,6 +29,10 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [CeilToFloat](#CeilToFloat)
|
||||||
|
- [CeilToString](#CeilToString)
|
||||||
|
- [FloorToFloat](#FloorToFloat)
|
||||||
|
- [FloorToString](#FloorToString)
|
||||||
- [AngleToRadian](#AngleToRadian)
|
- [AngleToRadian](#AngleToRadian)
|
||||||
- [RadianToAngle](#RadianToAngle)
|
- [RadianToAngle](#RadianToAngle)
|
||||||
- [PointDistance](#PointDistance)
|
- [PointDistance](#PointDistance)
|
||||||
@@ -240,6 +244,150 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToFloat">CeilToFloat</span>
|
||||||
|
|
||||||
|
<p>Round float up n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToFloat(x float64, n int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToString">CeilToString</span>
|
||||||
|
|
||||||
|
<p>Round float up n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString(x float64, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToString(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToString(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToFloat">FloorToFloat</span>
|
||||||
|
|
||||||
|
<p>Round float down n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString(x float64, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToString">FloorToString</span>
|
||||||
|
|
||||||
|
<p>Round float down n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString(x float64, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToString(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToString(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="AngleToRadian">AngleToRadian</span>
|
### <span id="AngleToRadian">AngleToRadian</span>
|
||||||
|
|
||||||
<p>Converts angle value to radian value.</p>
|
<p>Converts angle value to radian value.</p>
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [CeilToFloat](#CeilToFloat)
|
||||||
|
- [CeilToString](#CeilToString)
|
||||||
|
- [FloorToFloat](#FloorToFloat)
|
||||||
|
- [FloorToString](#FloorToString)
|
||||||
- [AngleToRadian](#AngleToRadian)
|
- [AngleToRadian](#AngleToRadian)
|
||||||
- [RadianToAngle](#RadianToAngle)
|
- [RadianToAngle](#RadianToAngle)
|
||||||
- [PointDistance](#PointDistance)
|
- [PointDistance](#PointDistance)
|
||||||
@@ -240,6 +244,151 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToFloat">CeilToFloat</span>
|
||||||
|
|
||||||
|
<p>向上舍入(进一法),保留n位小数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToFloat(x float64, n int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToString">CeilToString</span>
|
||||||
|
|
||||||
|
<p>向上舍入(进一法),保留n位小数,返回字符串。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString(x float64, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToString(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToString(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToFloat">FloorToFloat</span>
|
||||||
|
|
||||||
|
<p>向下舍入(去尾法),保留n位小数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString(x float64, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToString">FloorToString</span>
|
||||||
|
|
||||||
|
<p>向下舍入(去尾法),保留n位小数,返回字符串。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString(x float64, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToString(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToString(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AngleToRadian">AngleToRadian</span>
|
### <span id="AngleToRadian">AngleToRadian</span>
|
||||||
|
|
||||||
<p>将角度值转为弧度值</p>
|
<p>将角度值转为弧度值</p>
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import (
|
|||||||
- [Union](#Union)
|
- [Union](#Union)
|
||||||
- [UpdateByIndex](#UpdateByIndex)
|
- [UpdateByIndex](#UpdateByIndex)
|
||||||
- [Without](#Without)
|
- [Without](#Without)
|
||||||
|
- [Join](#Join)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -1172,3 +1173,36 @@ func main() {
|
|||||||
fmt.Println(res) //[]int{3, 4, 5}
|
fmt.Println(res) //[]int{3, 4, 5}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Join">Join</span>
|
||||||
|
|
||||||
|
<p>Join the slice item with specify separator.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Join(slice interface{}, separator string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
result1 := slice.Join(nums, ",")
|
||||||
|
result2 := slice.Join(nums, "-")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1,2,3,4,5
|
||||||
|
// 1-2-3-4-5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ import (
|
|||||||
- [Union](#Union)
|
- [Union](#Union)
|
||||||
- [UpdateByIndex](#UpdateByIndex)
|
- [UpdateByIndex](#UpdateByIndex)
|
||||||
- [Without](#Without)
|
- [Without](#Without)
|
||||||
|
- [Join](#Join)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -1168,3 +1170,36 @@ func main() {
|
|||||||
fmt.Println(res) //[]int{3, 4, 5}
|
fmt.Println(res) //[]int{3, 4, 5}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Join">Join</span>
|
||||||
|
|
||||||
|
<p>用指定的分隔符链接切片元素。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Join(slice interface{}, separator string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
result1 := slice.Join(nums, ",")
|
||||||
|
result2 := slice.Join(nums, "-")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1,2,3,4,5
|
||||||
|
// 1-2-3-4-5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ import (
|
|||||||
- [SplitAndTrim](#SplitAndTrim)
|
- [SplitAndTrim](#SplitAndTrim)
|
||||||
- [HideString](#HideString)
|
- [HideString](#HideString)
|
||||||
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
||||||
|
- [SubInBetween](#SubInBetween)
|
||||||
|
- [HammingDistance](#HammingDistance)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -1274,3 +1276,68 @@ func main() {
|
|||||||
// hello world
|
// hello world
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="SubInBetween">SubInBetween</span>
|
||||||
|
|
||||||
|
<p>Return substring between the start and end position(excluded) of source string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SubInBetween(str string, start string, end string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "abcde"
|
||||||
|
|
||||||
|
result1 := strutil.SubInBetween(str, "", "de")
|
||||||
|
result2 := strutil.SubInBetween(str, "a", "d")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// abc
|
||||||
|
// bc
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="HammingDistance">HammingDistance</span>
|
||||||
|
|
||||||
|
<p>HammingDistance calculates the Hamming distance between two strings. The Hamming distance is the number of positions at which the corresponding symbols are different.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
HammingDistance(a, b string) (int, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
result1, _ := strutil.HammingDistance("de", "de")
|
||||||
|
result2, _ := strutil.HammingDistance("a", "d")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -58,6 +58,8 @@ import (
|
|||||||
- [SplitAndTrim](#SplitAndTrim)
|
- [SplitAndTrim](#SplitAndTrim)
|
||||||
- [HideString](#HideString)
|
- [HideString](#HideString)
|
||||||
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
||||||
|
- [SubInBetween](#SubInBetween)
|
||||||
|
- [HammingDistance](#HammingDistance)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -1307,3 +1309,68 @@ func main() {
|
|||||||
// hello world
|
// hello world
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="SubInBetween">SubInBetween</span>
|
||||||
|
|
||||||
|
<p>获取字符串中指定的起始字符串start和终止字符串end直接的子字符串。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SubInBetween(str string, start string, end string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
str := "abcde"
|
||||||
|
|
||||||
|
result1 := strutil.SubInBetween(str, "", "de")
|
||||||
|
result2 := strutil.SubInBetween(str, "a", "d")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// abc
|
||||||
|
// bc
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="HammingDistance">HammingDistance</span>
|
||||||
|
|
||||||
|
<p>计算两个字符串之间的汉明距离。汉明距离是指对应符号不同的位置数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
HammingDistance(a, b string) (int, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
result1, _ := strutil.HammingDistance("de", "de")
|
||||||
|
result2, _ := strutil.HammingDistance("a", "d")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -54,7 +54,16 @@ import (
|
|||||||
- [IsZeroValue](#IsZeroValue)
|
- [IsZeroValue](#IsZeroValue)
|
||||||
- [IsGBK](#IsGBK)
|
- [IsGBK](#IsGBK)
|
||||||
- [IsASCII](#IsASCII)
|
- [IsASCII](#IsASCII)
|
||||||
- [IsAIsPrintableSCII](#IsPrintable)
|
- [IsPrintable](#IsPrintable)
|
||||||
|
- [IsBin](#IsBin)
|
||||||
|
- [IsHex](#IsHex)
|
||||||
|
- [IsBase64URL](#IsBase64URL)
|
||||||
|
- [IsJWT](#IsJWT)
|
||||||
|
- [IsVisa](#IsVisa)
|
||||||
|
- [IsMasterCard](#IsMasterCard)
|
||||||
|
- [IsAmericanExpress](#IsAmericanExpress)
|
||||||
|
- [IsUnionPay](#IsUnionPay)
|
||||||
|
- [IsChinaUnionPay](#IsChinaUnionPay)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -1026,4 +1035,301 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsBin">IsBin</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid binary value or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsBin(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsBin("0101")
|
||||||
|
result2 := validator.IsBin("0b1101")
|
||||||
|
result3 := validator.IsBin("b1101")
|
||||||
|
result4 := validator.IsBin("1201")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsHex">IsHex</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid hexadecimal value or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsHex(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsHex("0xabcde")
|
||||||
|
result2 := validator.IsHex("0XABCDE")
|
||||||
|
result3 := validator.IsHex("cdfeg")
|
||||||
|
result4 := validator.IsHex("0xcdfeg")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsBase64URL">IsBase64URL</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid URL-safe Base64 encoded string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsBase64URL(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ")
|
||||||
|
result2 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ==")
|
||||||
|
result3 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ=")
|
||||||
|
result4 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ===")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsJWT">IsJWT</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is is a valid JSON Web Token (JWT).</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsJWT(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibWVzc2FnZSI6IlB1dGluIGlzIGFic29sdXRlIHNoaXQiLCJpYXQiOjE1MTYyMzkwMjJ9.wkLWA5GtCpWdxNOrRse8yHZgORDgf8TpJp73WUQb910")
|
||||||
|
result2 := validator.IsJWT("abc")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsVisa">IsVisa</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid visa card nubmer or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsVisa(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsVisa("4111111111111111")
|
||||||
|
result2 := validator.IsVisa("123")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsMasterCard">IsMasterCard</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid mastercard nubmer or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsMasterCard(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsMasterCard("5425233430109903")
|
||||||
|
result2 := validator.IsMasterCard("4111111111111111")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsAmericanExpress">IsAmericanExpress</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid american express nubmer or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsAmericanExpress(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsAmericanExpress("342883359122187")
|
||||||
|
result2 := validator.IsAmericanExpress("3782822463100007")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsUnionPay">IsVisa</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid union pay nubmer or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsUnionPay(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsUnionPay("6221263430109903")
|
||||||
|
result2 := validator.IsUnionPay("3782822463100007")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsChinaUnionPay">IsChinaUnionPay</span>
|
||||||
|
|
||||||
|
<p>Checks if a give string is a valid china union pay nubmer or not.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsChinaUnionPay(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsChinaUnionPay("6250941006528599")
|
||||||
|
result2 := validator.IsChinaUnionPay("3782822463100007")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -55,6 +55,15 @@ import (
|
|||||||
- [IsGBK](#IsGBK)
|
- [IsGBK](#IsGBK)
|
||||||
- [IsASCII](#IsASCII)
|
- [IsASCII](#IsASCII)
|
||||||
- [IsPrintable](#IsPrintable)
|
- [IsPrintable](#IsPrintable)
|
||||||
|
- [IsBin](#IsBin)
|
||||||
|
- [IsHex](#IsHex)
|
||||||
|
- [IsBase64URL](#IsBase64URL)
|
||||||
|
- [IsJWT](#IsJWT)
|
||||||
|
- [IsVisa](#IsVisa)
|
||||||
|
- [IsMasterCard](#IsMasterCard)
|
||||||
|
- [IsAmericanExpress](#IsAmericanExpress)
|
||||||
|
- [IsUnionPay](#IsUnionPay)
|
||||||
|
- [IsChinaUnionPay](#IsChinaUnionPay)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -958,6 +967,7 @@ func main() {
|
|||||||
fmt.Println("data encoding is unknown")
|
fmt.Println("data encoding is unknown")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="IsASCII">IsASCII</span>
|
### <span id="IsASCII">IsASCII</span>
|
||||||
|
|
||||||
<p>验证字符串全部为ASCII字符。</p>
|
<p>验证字符串全部为ASCII字符。</p>
|
||||||
@@ -1036,4 +1046,301 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsBin">IsBin</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的二进制数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsBin(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsBin("0101")
|
||||||
|
result2 := validator.IsBin("0b1101")
|
||||||
|
result3 := validator.IsBin("b1101")
|
||||||
|
result4 := validator.IsBin("1201")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsHex">IsHex</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的十六进制数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsHex(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsHex("0xabcde")
|
||||||
|
result2 := validator.IsHex("0XABCDE")
|
||||||
|
result3 := validator.IsHex("cdfeg")
|
||||||
|
result4 := validator.IsHex("0xcdfeg")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsBase64URL">IsBase64URL</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的base64 url。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsBase64URL(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ")
|
||||||
|
result2 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ==")
|
||||||
|
result3 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ=")
|
||||||
|
result4 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ===")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsJWT">IsJWT</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的JSON Web Token (JWT)。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsJWT(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibWVzc2FnZSI6IlB1dGluIGlzIGFic29sdXRlIHNoaXQiLCJpYXQiOjE1MTYyMzkwMjJ9.wkLWA5GtCpWdxNOrRse8yHZgORDgf8TpJp73WUQb910")
|
||||||
|
result2 := validator.IsJWT("abc")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsVisa">IsVisa</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的visa卡号。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsVisa(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsVisa("4111111111111111")
|
||||||
|
result2 := validator.IsVisa("123")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsMasterCard">IsMasterCard</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的MasterCard卡号。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsMasterCard(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsMasterCard("5425233430109903")
|
||||||
|
result2 := validator.IsMasterCard("4111111111111111")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsAmericanExpress">IsAmericanExpress</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的American Express卡号。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsAmericanExpress(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsAmericanExpress("342883359122187")
|
||||||
|
result2 := validator.IsAmericanExpress("3782822463100007")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsUnionPay">IsUnionPay</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的美国银联卡号。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsUnionPay(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsUnionPay("6221263430109903")
|
||||||
|
result2 := validator.IsUnionPay("3782822463100007")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsChinaUnionPay">IsChinaUnionPay</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是有效的中国银联卡号。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsChinaUnionPay(v string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsChinaUnionPay("6250941006528599")
|
||||||
|
result2 := validator.IsChinaUnionPay("3782822463100007")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
348
fileutil/file.go
348
fileutil/file.go
@@ -17,12 +17,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsExist checks if a file or directory exists
|
// IsExist checks if a file or directory exists
|
||||||
@@ -50,7 +54,7 @@ func CreateFile(path string) bool {
|
|||||||
|
|
||||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
|
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
|
||||||
func CreateDir(absPath string) error {
|
func CreateDir(absPath string) error {
|
||||||
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
|
return os.MkdirAll(absPath, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDir checks if the path is directory or not
|
// IsDir checks if the path is directory or not
|
||||||
@@ -168,7 +172,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
|
||||||
@@ -178,7 +190,97 @@ func Zip(fpath string, destPath string) error {
|
|||||||
archive := zip.NewWriter(zipFile)
|
archive := zip.NewWriter(zipFile)
|
||||||
defer archive.Close()
|
defer archive.Close()
|
||||||
|
|
||||||
return addFileToArchive(fpath, archive)
|
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 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := zip.FileInfoHeader(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Name = strings.TrimPrefix(path, filepath.Dir(fpath)+"/")
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
header.Name += "/"
|
||||||
|
} else {
|
||||||
|
header.Method = zip.Deflate
|
||||||
|
writer, err := archive.CreateHeader(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
if _, err := io.Copy(writer, file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnZip unzip the file and save it to destPath
|
// UnZip unzip the file and save it to destPath
|
||||||
@@ -259,7 +361,7 @@ func ZipAppendEntry(fpath string, destPath string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFileToArchive(fpath, archive)
|
err = addFileToArchive1(fpath, archive)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -281,41 +383,6 @@ func ZipAppendEntry(fpath string, destPath string) error {
|
|||||||
return CopyFile(tempFile.Name(), destPath)
|
return CopyFile(tempFile.Name(), destPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addFileToArchive(fpath string, archive *zip.Writer) error {
|
|
||||||
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
header, err := zip.FileInfoHeader(info)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
header.Name = strings.TrimPrefix(path, filepath.Dir(fpath)+"/")
|
|
||||||
|
|
||||||
if info.IsDir() {
|
|
||||||
header.Name += "/"
|
|
||||||
} else {
|
|
||||||
header.Method = zip.Deflate
|
|
||||||
writer, err := archive.CreateHeader(header)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
if _, err := io.Copy(writer, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeFilepathJoin(path1, path2 string) (string, error) {
|
func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||||
relPath, err := filepath.Rel(".", path2)
|
relPath, err := filepath.Rel(".", path2)
|
||||||
if err != nil || strings.HasPrefix(relPath, "..") {
|
if err != nil || strings.HasPrefix(relPath, "..") {
|
||||||
@@ -386,7 +453,7 @@ func CurrentPath() string {
|
|||||||
var absPath string
|
var absPath string
|
||||||
_, filename, _, ok := runtime.Caller(1)
|
_, filename, _, ok := runtime.Caller(1)
|
||||||
if ok {
|
if ok {
|
||||||
absPath = path.Dir(filename)
|
absPath = filepath.Dir(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
return absPath
|
return absPath
|
||||||
@@ -460,15 +527,19 @@ func Sha(filepath string, shaType ...int) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReadCsvFile read file content into slice.
|
// ReadCsvFile read file content into slice.
|
||||||
func ReadCsvFile(filepath string) ([][]string, error) {
|
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error) {
|
||||||
f, err := os.Open(filepath)
|
f, err := os.Open(filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
csvReader := csv.NewReader(f)
|
reader := csv.NewReader(f)
|
||||||
records, err := csvReader.ReadAll()
|
if len(delimiter) > 0 {
|
||||||
|
reader.Comma = delimiter[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
records, err := reader.ReadAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -477,7 +548,7 @@ func ReadCsvFile(filepath string) ([][]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteCsvFile write content to target csv file.
|
// WriteCsvFile write content to target csv file.
|
||||||
func WriteCsvFile(filepath string, records [][]string, append bool) error {
|
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error {
|
||||||
flag := os.O_RDWR | os.O_CREATE
|
flag := os.O_RDWR | os.O_CREATE
|
||||||
|
|
||||||
if append {
|
if append {
|
||||||
@@ -492,11 +563,90 @@ func WriteCsvFile(filepath string, records [][]string, append bool) error {
|
|||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
writer := csv.NewWriter(f)
|
writer := csv.NewWriter(f)
|
||||||
writer.Comma = ','
|
// 设置默认分隔符为逗号,除非另外指定
|
||||||
|
if len(delimiter) > 0 {
|
||||||
|
writer.Comma = delimiter[0]
|
||||||
|
} else {
|
||||||
|
writer.Comma = ','
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历所有记录并处理包含分隔符或双引号的单元格
|
||||||
|
for i := range records {
|
||||||
|
for j := range records[i] {
|
||||||
|
records[i][j] = escapeCSVField(records[i][j], writer.Comma)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return writer.WriteAll(records)
|
return writer.WriteAll(records)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// escapeCSVField 处理单元格内容,如果包含分隔符,则用双引号包裹
|
||||||
|
func escapeCSVField(field string, delimiter rune) string {
|
||||||
|
// 替换所有的双引号为两个双引号
|
||||||
|
escapedField := strings.ReplaceAll(field, "\"", "\"\"")
|
||||||
|
|
||||||
|
// 如果字段包含分隔符、双引号或换行符,用双引号包裹整个字段
|
||||||
|
if strings.ContainsAny(escapedField, string(delimiter)+"\"\n") {
|
||||||
|
escapedField = fmt.Sprintf("\"%s\"", escapedField)
|
||||||
|
}
|
||||||
|
|
||||||
|
return escapedField
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteMapsToCsv write slice of map to csv file.
|
||||||
|
// Play: https://go.dev/play/p/umAIomZFV1c
|
||||||
|
// filepath: Path to the CSV file.
|
||||||
|
// records: Slice of maps to be written. the value of map should be basic type.
|
||||||
|
// the maps will be sorted by key in alphabeta order, then be written into csv file.
|
||||||
|
// appendToExistingFile: If true, data will be appended to the file if it exists.
|
||||||
|
// delimiter: Delimiter to use in the CSV file.
|
||||||
|
// headers: order of the csv column headers, needs to be consistent with the key of the map.
|
||||||
|
func WriteMapsToCsv(filepath string, records []map[string]interface{}, appendToExistingFile bool, delimiter rune, headers ...[]string) error {
|
||||||
|
for _, record := range records {
|
||||||
|
for _, value := range record {
|
||||||
|
if !isCsvSupportedType(value) {
|
||||||
|
return errors.New("unsupported value type detected; only basic types are supported: \nbool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var columnHeaders []string
|
||||||
|
if len(headers) > 0 {
|
||||||
|
columnHeaders = headers[0]
|
||||||
|
} else {
|
||||||
|
for key := range records[0] {
|
||||||
|
columnHeaders = append(columnHeaders, key)
|
||||||
|
}
|
||||||
|
// sort keys in alphabeta order
|
||||||
|
sort.Strings(columnHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
var datasToWrite [][]string
|
||||||
|
if !appendToExistingFile {
|
||||||
|
datasToWrite = append(datasToWrite, columnHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, record := range records {
|
||||||
|
var row []string
|
||||||
|
for _, h := range columnHeaders {
|
||||||
|
row = append(row, fmt.Sprintf("%v", record[h]))
|
||||||
|
}
|
||||||
|
datasToWrite = append(datasToWrite, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteCsvFile(filepath, datasToWrite, appendToExistingFile, delimiter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the value of map which to be written into csv is basic type.
|
||||||
|
func isCsvSupportedType(v interface{}) bool {
|
||||||
|
switch v.(type) {
|
||||||
|
case bool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WriteStringToFile write string to target file.
|
// WriteStringToFile write string to target file.
|
||||||
func WriteStringToFile(filepath string, content string, append bool) error {
|
func WriteStringToFile(filepath string, content string, append bool) error {
|
||||||
flag := os.O_RDWR | os.O_CREATE
|
flag := os.O_RDWR | os.O_CREATE
|
||||||
@@ -526,3 +676,109 @@ func WriteBytesToFile(filepath string, content []byte) error {
|
|||||||
_, err = f.Write(content)
|
_, err = f.Write(content)
|
||||||
return err
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChunkRead 从文件的指定偏移读取块并返回块内所有行
|
||||||
|
func ChunkRead(f *os.File, offset int64, size int, bufPool *sync.Pool) []string {
|
||||||
|
buf := bufPool.Get().([]byte)[:size] // 从Pool获取缓冲区并调整大小
|
||||||
|
n, err := f.ReadAt(buf, offset) // 从指定偏移读取数据到缓冲区
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
buf = buf[:n] // 调整切片以匹配实际读取的字节数
|
||||||
|
|
||||||
|
var lines []string
|
||||||
|
var lineStart int
|
||||||
|
for i, b := range buf {
|
||||||
|
if b == '\n' {
|
||||||
|
line := string(buf[lineStart:i]) // 不包括换行符
|
||||||
|
lines = append(lines, line)
|
||||||
|
lineStart = i + 1 // 设置下一行的开始
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if lineStart < len(buf) { // 处理块末尾的行
|
||||||
|
line := string(buf[lineStart:])
|
||||||
|
lines = append(lines, line)
|
||||||
|
}
|
||||||
|
bufPool.Put(buf) // 读取完成后,将缓冲区放回Pool
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// 并行读取文件并将每个块的行发送到指定通道
|
||||||
|
// filePath 文件路径
|
||||||
|
// ChunkSizeMB 分块的大小(单位MB,设置为0时使用默认100MB),设置过大反而不利,视情调整
|
||||||
|
// MaxGoroutine 并发读取分块的数量,设置为0时使用CPU核心数
|
||||||
|
// linesCh用于接收返回结果的通道。
|
||||||
|
func ParallelChunkRead(filePath string, linesCh chan<- []string, ChunkSizeMB, MaxGoroutine int) {
|
||||||
|
if ChunkSizeMB == 0 {
|
||||||
|
ChunkSizeMB = 100
|
||||||
|
}
|
||||||
|
ChunkSize := ChunkSizeMB * 1024 * 1024
|
||||||
|
// 内存复用
|
||||||
|
bufPool := sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, 0, ChunkSize)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if MaxGoroutine == 0 {
|
||||||
|
MaxGoroutine = runtime.NumCPU() // 设置为0时使用CPU核心数
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to open file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
info, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to get file info: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
chunkOffsetCh := make(chan int64, MaxGoroutine)
|
||||||
|
|
||||||
|
// 分配工作
|
||||||
|
go func() {
|
||||||
|
for i := int64(0); i < info.Size(); i += int64(ChunkSize) {
|
||||||
|
chunkOffsetCh <- i
|
||||||
|
}
|
||||||
|
close(chunkOffsetCh)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 启动工作协程
|
||||||
|
for i := 0; i < MaxGoroutine; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
for chunkOffset := range chunkOffsetCh {
|
||||||
|
linesCh <- ChunkRead(f, chunkOffset, ChunkSize, &bufPool)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待所有解析完成后关闭行通道
|
||||||
|
wg.Wait()
|
||||||
|
close(linesCh)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package fileutil
|
package fileutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -294,7 +295,11 @@ func TestSha(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSha")
|
assert := internal.NewAssert(t, "TestSha")
|
||||||
|
|
||||||
sha1, err := Sha("./testdata/test.txt", 1)
|
sha1, err := Sha("./testdata/test.txt", 1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
sha256, err := Sha("./testdata/test.txt", 256)
|
sha256, err := Sha("./testdata/test.txt", 256)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
sha512, err := Sha("./testdata/test.txt", 512)
|
sha512, err := Sha("./testdata/test.txt", 512)
|
||||||
|
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
@@ -337,6 +342,31 @@ func TestWriteCsvFile(t *testing.T) {
|
|||||||
assert.Equal("Lili", content[0][0])
|
assert.Equal("Lili", content[0][0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteMapsToCsv(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestWriteMapsToCSV")
|
||||||
|
|
||||||
|
csvFilePath := "./testdata/test4.csv"
|
||||||
|
records := []map[string]interface{}{
|
||||||
|
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||||
|
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := []string{"Name", "Age", "Gender"}
|
||||||
|
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
content, err := ReadCsvFile(csvFilePath, ';')
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(3, len(content))
|
||||||
|
assert.Equal(3, len(content[0]))
|
||||||
|
assert.Equal("Lili", content[1][0])
|
||||||
|
assert.Equal("22", content[1][1])
|
||||||
|
assert.Equal("female", content[1][2])
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteStringToFile(t *testing.T) {
|
func TestWriteStringToFile(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestWriteStringToFile")
|
assert := internal.NewAssert(t, "TestWriteStringToFile")
|
||||||
|
|
||||||
@@ -401,3 +431,21 @@ func TestWriteBytesToFile(t *testing.T) {
|
|||||||
|
|
||||||
os.Remove(filepath)
|
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))
|
||||||
|
}
|
||||||
|
|||||||
1
fileutil/testdata/test1.csv
vendored
1
fileutil/testdata/test1.csv
vendored
@@ -1,2 +1,3 @@
|
|||||||
Lili,22,female
|
Lili,22,female
|
||||||
Jim,21,male
|
Jim,21,male
|
||||||
|
|
||||||
|
|||||||
|
3
fileutil/testdata/test4.csv
vendored
Normal file
3
fileutil/testdata/test4.csv
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Name;Age;Gender
|
||||||
|
Lili;22;female
|
||||||
|
Jim;21;male
|
||||||
|
@@ -8,41 +8,36 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/convertor"
|
"github.com/duke-git/lancet/convertor"
|
||||||
"github.com/duke-git/lancet/strutil"
|
|
||||||
"github.com/duke-git/lancet/validator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Comma add comma to a number value by every 3 numbers from right. ahead by symbol char.
|
// 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
|
// if value is invalid number string eg "aa", return empty string
|
||||||
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
||||||
func Comma(value interface{}, symbol string) string {
|
func Comma(value interface{}, symbol string) string {
|
||||||
if validator.IsInt(value) {
|
numString := convertor.ToString(value)
|
||||||
v, err := convertor.ToInt(value)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return symbol + commaInt(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if validator.IsFloat(value) {
|
_, err := strconv.ParseFloat(numString, 64)
|
||||||
v, err := convertor.ToFloat(value)
|
if err != nil {
|
||||||
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 ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
index := strings.Index(numString, ".")
|
||||||
|
if index == -1 {
|
||||||
|
index = len(numString)
|
||||||
|
}
|
||||||
|
|
||||||
|
for index > 3 {
|
||||||
|
index = index - 3
|
||||||
|
numString = numString[:index] + "," + numString[index:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol + numString
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pretty data to JSON string.
|
// Pretty data to JSON string.
|
||||||
@@ -177,3 +172,50 @@ func ParseDecimalBytes(size string) (uint64, error) {
|
|||||||
func ParseBinaryBytes(size string) (uint64, error) {
|
func ParseBinaryBytes(size string) (uint64, error) {
|
||||||
return parseBytes(size, "binary")
|
return parseBytes(size, "binary")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see https://github.com/dustin/go-humanize/blob/master/bytes.go
|
||||||
|
func parseBytes(s string, kind string) (uint64, error) {
|
||||||
|
lastDigit := 0
|
||||||
|
hasComma := false
|
||||||
|
for _, r := range s {
|
||||||
|
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if r == ',' {
|
||||||
|
hasComma = true
|
||||||
|
}
|
||||||
|
lastDigit++
|
||||||
|
}
|
||||||
|
|
||||||
|
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,134 +0,0 @@
|
|||||||
package formatter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// see https://github.com/dustin/go-humanize/blob/master/bytes.go
|
|
||||||
func parseBytes(s string, kind string) (uint64, error) {
|
|
||||||
lastDigit := 0
|
|
||||||
hasComma := false
|
|
||||||
for _, r := range s {
|
|
||||||
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if r == ',' {
|
|
||||||
hasComma = true
|
|
||||||
}
|
|
||||||
lastDigit++
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@@ -91,6 +91,34 @@ func TruncRound(x float64, n int) float64 {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FloorToFloat round down to n decimal places.
|
||||||
|
func FloorToFloat(x float64, n int) float64 {
|
||||||
|
return math.Floor(x*math.Pow(10, float64(n))) / math.Pow(10.0, float64(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloorToString round down to n decimal places.
|
||||||
|
func FloorToString(x float64, n int) string {
|
||||||
|
tmp := math.Pow(10.0, float64(n))
|
||||||
|
x *= tmp
|
||||||
|
x = math.Floor(x)
|
||||||
|
res := strconv.FormatFloat(x/tmp, 'f', n, 64)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// CeilToFloat round up to n decimal places.
|
||||||
|
func CeilToFloat(x float64, n int) float64 {
|
||||||
|
pow10n := math.Pow10(n)
|
||||||
|
return math.Ceil(x*pow10n) / pow10n
|
||||||
|
}
|
||||||
|
|
||||||
|
// CeilToString round up to n decimal places.
|
||||||
|
func CeilToString(x float64, n int) string {
|
||||||
|
multiplier := math.Pow(10, float64(n))
|
||||||
|
rounded := math.Ceil(x*multiplier) / multiplier
|
||||||
|
|
||||||
|
return fmt.Sprintf("%.*f", n, rounded)
|
||||||
|
}
|
||||||
|
|
||||||
// AngleToRadian converts angle value to radian value.
|
// AngleToRadian converts angle value to radian value.
|
||||||
func AngleToRadian(angle float64) float64 {
|
func AngleToRadian(angle float64) float64 {
|
||||||
radian := angle * (math.Pi / 180)
|
radian := angle * (math.Pi / 180)
|
||||||
|
|||||||
@@ -180,3 +180,46 @@ func TestLog(t *testing.T) {
|
|||||||
assert.EqualValues(3, TruncRound(Log(27, 3), 0))
|
assert.EqualValues(3, TruncRound(Log(27, 3), 0))
|
||||||
assert.EqualValues(2.32, TruncRound(Log(5, 2), 2))
|
assert.EqualValues(2.32, TruncRound(Log(5, 2), 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFloorToFloat(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFloorToFloat")
|
||||||
|
|
||||||
|
assert.Equal(3.14, FloorToFloat(3.14159, 2))
|
||||||
|
assert.Equal(3.141, FloorToFloat(3.14159, 3))
|
||||||
|
assert.Equal(5.0, FloorToFloat(5, 4))
|
||||||
|
assert.Equal(2.0, FloorToFloat(9/4, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloorToString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFloorToString")
|
||||||
|
|
||||||
|
assert.Equal("3.14", FloorToString(3.14159, 2))
|
||||||
|
assert.Equal("3.141", FloorToString(3.14159, 3))
|
||||||
|
assert.Equal("5.0000", FloorToString(5, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCeilToFloat(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestCeilToFloat")
|
||||||
|
|
||||||
|
assert.Equal(3.15, CeilToFloat(3.14159, 2))
|
||||||
|
assert.Equal(3.142, CeilToFloat(3.14159, 3))
|
||||||
|
assert.Equal(5.0, CeilToFloat(5, 4))
|
||||||
|
assert.Equal(0.15, CeilToFloat(float64(1)/float64(7), 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCeilToString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestCeilToFloat")
|
||||||
|
|
||||||
|
assert.Equal("3.15", CeilToString(3.14159, 2))
|
||||||
|
assert.Equal("3.142", CeilToString(3.14159, 3))
|
||||||
|
assert.Equal("5.0000", CeilToString(5, 4))
|
||||||
|
assert.Equal("0.15", CeilToString(float64(1)/float64(7), 2))
|
||||||
|
}
|
||||||
|
|||||||
260
random/random.go
260
random/random.go
@@ -8,22 +8,30 @@ import (
|
|||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/mathutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NUMERAL = "0123456789"
|
MaximumCapacity = math.MaxInt>>1 + 1
|
||||||
LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz"
|
Numeral = "0123456789"
|
||||||
UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||||
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
SymbolChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var rn = rand.NewSource(time.Now().UnixNano())
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandInt generate random int between min and max, maybe min, not be max
|
// RandInt generate random int between [min, max).
|
||||||
func RandInt(min, max int) int {
|
func RandInt(min, max int) int {
|
||||||
if min == max {
|
if min == max {
|
||||||
return min
|
return min
|
||||||
@@ -36,7 +44,23 @@ func RandInt(min, max int) int {
|
|||||||
return rand.Intn(max-min) + min
|
return rand.Intn(max-min) + min
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandBytes generate random byte slice
|
// RandFloat generate random float64 number between [min, max) with specific precision.
|
||||||
|
func RandFloat(min, max float64, precision int) float64 {
|
||||||
|
if min == max {
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
|
||||||
|
if max < min {
|
||||||
|
min, max = max, min
|
||||||
|
}
|
||||||
|
|
||||||
|
n := rand.Float64()*(max-min) + min
|
||||||
|
|
||||||
|
return mathutil.RoundToFloat(n, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandBytes generate random byte slice.
|
||||||
|
// Play: https://go.dev/play/p/EkiLESeXf8d
|
||||||
func RandBytes(length int) []byte {
|
func RandBytes(length int) []byte {
|
||||||
if length < 1 {
|
if length < 1 {
|
||||||
return []byte{}
|
return []byte{}
|
||||||
@@ -46,48 +70,99 @@ func RandBytes(length int) []byte {
|
|||||||
if _, err := io.ReadFull(crand.Reader, b); err != nil {
|
if _, err := io.ReadFull(crand.Reader, b); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandString generate random string
|
// RandString generate random alpha string of specified length.
|
||||||
func RandString(length int) string {
|
func RandString(length int) string {
|
||||||
return random(LETTERS, length)
|
return random(Letters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandUpper generate a random upper case string
|
// RandUpper generate a random upper case string of specified length.
|
||||||
func RandUpper(length int) string {
|
func RandUpper(length int) string {
|
||||||
return random(UPPER_LETTERS, length)
|
return random(UpperLetters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandLower generate a random lower case string
|
// RandLower generate a random lower case string of specified length.
|
||||||
func RandLower(length int) string {
|
func RandLower(length int) string {
|
||||||
return random(LOWER_LETTERS, length)
|
return random(LowwerLetters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandNumeral generate a random numeral string
|
// RandNumeral generate a random numeral string of specified length.
|
||||||
func RandNumeral(length int) string {
|
func RandNumeral(length int) string {
|
||||||
return random(NUMERAL, length)
|
return random(Numeral, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandNumeralOrLetter generate a random numeral or letter string
|
// RandNumeralOrLetter generate a random numeral or alpha string of specified length.
|
||||||
func RandNumeralOrLetter(length int) string {
|
func RandNumeralOrLetter(length int) string {
|
||||||
return random(NUMERAL+LETTERS, length)
|
return random(Numeral+Letters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// random generate a random string based on given string range
|
// RandSymbolChar generate a random symbol char of specified length.
|
||||||
func random(s string, length int) string {
|
// symbol chars: !@#$%^&*()_+-=[]{}|;':\",./<>?.
|
||||||
b := make([]byte, length)
|
func RandSymbolChar(length int) string {
|
||||||
|
return random(SymbolChars, length)
|
||||||
|
}
|
||||||
|
|
||||||
// fix: https://github.com/duke-git/lancet/issues/75
|
// nearestPowerOfTwo 返回一个大于等于cap的最近的2的整数次幂,参考java8的hashmap的tableSizeFor函数
|
||||||
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
func nearestPowerOfTwo(cap int) int {
|
||||||
|
n := cap - 1
|
||||||
for i := range b {
|
n |= n >> 1
|
||||||
b[i] = s[rand.Int63()%int64(len(s))]
|
n |= n >> 2
|
||||||
|
n |= n >> 4
|
||||||
|
n |= n >> 8
|
||||||
|
n |= n >> 16
|
||||||
|
if n < 0 {
|
||||||
|
return 1
|
||||||
|
} else if n >= MaximumCapacity {
|
||||||
|
return MaximumCapacity
|
||||||
}
|
}
|
||||||
return string(b)
|
return n + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// UUIdV4 generate a random UUID of version 4 according to RFC 4122
|
// random generate a random string based on given string range.
|
||||||
|
func random(s string, length int) string {
|
||||||
|
// 仿照strings.Builder
|
||||||
|
// 创建一个长度为 length 的字节切片
|
||||||
|
bytes := make([]byte, length)
|
||||||
|
strLength := len(s)
|
||||||
|
if strLength <= 0 {
|
||||||
|
return ""
|
||||||
|
} else if strLength == 1 {
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
bytes[i] = s[0]
|
||||||
|
}
|
||||||
|
return *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
}
|
||||||
|
// s的字符需要使用多少个比特位数才能表示完
|
||||||
|
// letterIdBits := int(math.Ceil(math.Log2(strLength))),下面比上面的代码快
|
||||||
|
letterIdBits := int(math.Log2(float64(nearestPowerOfTwo(strLength))))
|
||||||
|
// 最大的字母id掩码
|
||||||
|
var letterIdMask int64 = 1<<letterIdBits - 1
|
||||||
|
// 可用次数的最大值
|
||||||
|
letterIdMax := 63 / letterIdBits
|
||||||
|
// 循环生成随机字符串
|
||||||
|
for i, cache, remain := length-1, rn.Int63(), letterIdMax; i >= 0; {
|
||||||
|
// 检查随机数生成器是否用尽所有随机数
|
||||||
|
if remain == 0 {
|
||||||
|
cache, remain = rn.Int63(), letterIdMax
|
||||||
|
}
|
||||||
|
// 从可用字符的字符串中随机选择一个字符
|
||||||
|
if idx := int(cache & letterIdMask); idx < strLength {
|
||||||
|
bytes[i] = s[idx]
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
// 右移比特位数,为下次选择字符做准备
|
||||||
|
cache >>= letterIdBits
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
// 仿照strings.Builder用unsafe包返回一个字符串,避免拷贝
|
||||||
|
// 将字节切片转换为字符串并返回
|
||||||
|
return *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
@@ -125,3 +200,136 @@ func RandUniqueIntSlice(n, min, max int) []int {
|
|||||||
|
|
||||||
return nums
|
return nums
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandFloats generate a slice of random float64 numbers of length n that do not repeat.
|
||||||
|
func RandFloats(n int, min, max float64, precision int) []float64 {
|
||||||
|
nums := make([]float64, n)
|
||||||
|
used := make(map[float64]struct{}, n)
|
||||||
|
for i := 0; i < n; {
|
||||||
|
r := RandFloat(min, max, precision)
|
||||||
|
if _, use := used[r]; use {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
used[r] = struct{}{}
|
||||||
|
nums[i] = r
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return nums
|
||||||
|
}
|
||||||
|
|
||||||
|
// const (
|
||||||
|
// NUMERAL = "0123456789"
|
||||||
|
// LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
// UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
// LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
// )
|
||||||
|
|
||||||
|
// var rn = rand.NewSource(time.Now().UnixNano())
|
||||||
|
|
||||||
|
// func init() {
|
||||||
|
// rand.Seed(time.Now().UnixNano())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // RandInt generate random int between min and max, maybe min, not be max
|
||||||
|
// func RandInt(min, max int) int {
|
||||||
|
// if min == max {
|
||||||
|
// return min
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if max < min {
|
||||||
|
// min, max = max, min
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return rand.Intn(max-min) + min
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // RandBytes generate random byte slice
|
||||||
|
// func RandBytes(length int) []byte {
|
||||||
|
// if length < 1 {
|
||||||
|
// return []byte{}
|
||||||
|
// }
|
||||||
|
// b := make([]byte, length)
|
||||||
|
|
||||||
|
// if _, err := io.ReadFull(crand.Reader, b); err != nil {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// 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
|
||||||
|
// func UUIdV4() (string, error) {
|
||||||
|
// uuid := make([]byte, 16)
|
||||||
|
|
||||||
|
// n, err := io.ReadFull(crand.Reader, uuid)
|
||||||
|
// if n != len(uuid) || err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// uuid[8] = uuid[8]&^0xc0 | 0x80
|
||||||
|
// uuid[6] = uuid[6]&^0xf0 | 0x40
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// }
|
||||||
|
|||||||
@@ -968,3 +968,16 @@ func AppendIfAbsent(slice interface{}, value interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
return out.Interface()
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -624,3 +624,15 @@ func TestAppendIfAbsent(t *testing.T) {
|
|||||||
assert.Equal([]string{"a", "b"}, AppendIfAbsent(str1, "a"))
|
assert.Equal([]string{"a", "b"}, AppendIfAbsent(str1, "a"))
|
||||||
assert.Equal([]string{"a", "b", "c"}, AppendIfAbsent(str1, "c"))
|
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,7 +5,7 @@
|
|||||||
package strutil
|
package strutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
@@ -121,37 +121,45 @@ func UpperSnakeCase(s string) string {
|
|||||||
|
|
||||||
// Before create substring in source string before position when char first appear
|
// Before create substring in source string before position when char first appear
|
||||||
func Before(s, char string) string {
|
func Before(s, char string) string {
|
||||||
if s == "" || char == "" {
|
i := strings.Index(s, char)
|
||||||
|
|
||||||
|
if s == "" || char == "" || i == -1 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
i := strings.Index(s, char)
|
|
||||||
return s[0:i]
|
return s[0:i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeLast create substring in source string before position when char last appear
|
// BeforeLast create substring in source string before position when char last appear
|
||||||
func BeforeLast(s, char string) string {
|
func BeforeLast(s, char string) string {
|
||||||
if s == "" || char == "" {
|
i := strings.LastIndex(s, char)
|
||||||
|
|
||||||
|
if s == "" || char == "" || i == -1 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
i := strings.LastIndex(s, char)
|
|
||||||
return s[0:i]
|
return s[0:i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// After create substring in source string after position when char first appear
|
// After create substring in source string after position when char first appear
|
||||||
func After(s, char string) string {
|
func After(s, char string) string {
|
||||||
if s == "" || char == "" {
|
i := strings.Index(s, char)
|
||||||
|
|
||||||
|
if s == "" || char == "" || i == -1 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
i := strings.Index(s, char)
|
|
||||||
return s[i+len(char):]
|
return s[i+len(char):]
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLast create substring in source string after position when char last appear
|
// AfterLast create substring in source string after position when char last appear
|
||||||
func AfterLast(s, char string) string {
|
func AfterLast(s, char string) string {
|
||||||
if s == "" || char == "" {
|
i := strings.LastIndex(s, char)
|
||||||
|
|
||||||
|
if s == "" || char == "" || i == -1 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
i := strings.LastIndex(s, char)
|
|
||||||
return s[i+len(char):]
|
return s[i+len(char):]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,10 +350,7 @@ func RemoveNonPrintable(str string) string {
|
|||||||
|
|
||||||
// StringToBytes converts a string to byte slice without a memory allocation.
|
// StringToBytes converts a string to byte slice without a memory allocation.
|
||||||
func StringToBytes(str string) (b []byte) {
|
func StringToBytes(str string) (b []byte) {
|
||||||
sh := *(*reflect.StringHeader)(unsafe.Pointer(&str))
|
return *(*[]byte)(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.
|
// BytesToString converts a byte slice to string without a memory allocation.
|
||||||
@@ -522,3 +527,35 @@ func RemoveWhiteSpace(str string, repalceAll bool) string {
|
|||||||
|
|
||||||
return strings.TrimSpace(str)
|
return strings.TrimSpace(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubInBetween return substring between the start and end position(excluded) of source string.
|
||||||
|
func SubInBetween(str string, start string, end string) string {
|
||||||
|
if _, after, ok := strings.Cut(str, start); ok {
|
||||||
|
if before, _, ok := strings.Cut(after, end); ok {
|
||||||
|
return before
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// HammingDistance calculates the Hamming distance between two strings.
|
||||||
|
// The Hamming distance is the number of positions at which the corresponding symbols are different.
|
||||||
|
// This func returns an error if the input strings are of unequal lengths.
|
||||||
|
func HammingDistance(a, b string) (int, error) {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return -1, errors.New("a length and b length are unequal")
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := []rune(a)
|
||||||
|
br := []rune(b)
|
||||||
|
|
||||||
|
var distance int
|
||||||
|
for i, codepoint := range ar {
|
||||||
|
if codepoint != br[i] {
|
||||||
|
distance++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return distance, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ func TestBefore(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestBefore")
|
assert := internal.NewAssert(t, "TestBefore")
|
||||||
|
|
||||||
assert.Equal("lancet", Before("lancet", ""))
|
assert.Equal("lancet", Before("lancet", ""))
|
||||||
|
assert.Equal("lancet", Before("lancet", "abcdef"))
|
||||||
assert.Equal("github.com", Before("github.com/test/lancet", "/"))
|
assert.Equal("github.com", Before("github.com/test/lancet", "/"))
|
||||||
assert.Equal("github.com/", Before("github.com/test/lancet", "test"))
|
assert.Equal("github.com/", Before("github.com/test/lancet", "test"))
|
||||||
}
|
}
|
||||||
@@ -215,16 +216,42 @@ func TestBeforeLast(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestBeforeLast")
|
assert := internal.NewAssert(t, "TestBeforeLast")
|
||||||
|
|
||||||
assert.Equal("lancet", BeforeLast("lancet", ""))
|
assert.Equal("lancet", BeforeLast("lancet", ""))
|
||||||
|
|
||||||
|
assert.Equal("lancet", BeforeLast("lancet", "abcdef"))
|
||||||
assert.Equal("github.com/test", BeforeLast("github.com/test/lancet", "/"))
|
assert.Equal("github.com/test", BeforeLast("github.com/test/lancet", "/"))
|
||||||
assert.Equal("github.com/test/", BeforeLast("github.com/test/test/lancet", "test"))
|
assert.Equal("github.com/test/", BeforeLast("github.com/test/test/lancet", "test"))
|
||||||
|
|
||||||
assert.NotEqual("github.com/", BeforeLast("github.com/test/test/lancet", "test"))
|
assert.NotEqual("github.com/", BeforeLast("github.com/test/test/lancet", "test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHammingDistance(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "HammingDistance")
|
||||||
|
|
||||||
|
hd := func(a, b string) int {
|
||||||
|
c, _ := HammingDistance(a, b)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(0, hd(" ", " "))
|
||||||
|
assert.Equal(1, hd(" ", "c"))
|
||||||
|
assert.Equal(1, hd("a", "d"))
|
||||||
|
assert.Equal(1, hd("a", " "))
|
||||||
|
assert.Equal(1, hd("a", "f"))
|
||||||
|
|
||||||
|
assert.Equal(0, hd("", ""))
|
||||||
|
assert.Equal(-1, hd("abc", "ab"))
|
||||||
|
assert.Equal(3, hd("abc", "def"))
|
||||||
|
assert.Equal(-1, hd("kitten", "sitting"))
|
||||||
|
assert.Equal(1, hd("ö", "ü"))
|
||||||
|
assert.Equal(0, hd("日本語", "日本語"))
|
||||||
|
assert.Equal(3, hd("日本語", "語日本"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestAfter(t *testing.T) {
|
func TestAfter(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestAfter")
|
assert := internal.NewAssert(t, "TestAfter")
|
||||||
|
|
||||||
assert.Equal("lancet", After("lancet", ""))
|
assert.Equal("lancet", After("lancet", ""))
|
||||||
|
assert.Equal("lancet", After("lancet", "abcdef"))
|
||||||
assert.Equal("test/lancet", After("github.com/test/lancet", "/"))
|
assert.Equal("test/lancet", After("github.com/test/lancet", "/"))
|
||||||
assert.Equal("/lancet", After("github.com/test/lancet", "test"))
|
assert.Equal("/lancet", After("github.com/test/lancet", "test"))
|
||||||
}
|
}
|
||||||
@@ -233,6 +260,7 @@ func TestAfterLast(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestAfterLast")
|
assert := internal.NewAssert(t, "TestAfterLast")
|
||||||
|
|
||||||
assert.Equal("lancet", AfterLast("lancet", ""))
|
assert.Equal("lancet", AfterLast("lancet", ""))
|
||||||
|
assert.Equal("lancet", AfterLast("lancet", "abcdef"))
|
||||||
assert.Equal("lancet", AfterLast("github.com/test/lancet", "/"))
|
assert.Equal("lancet", AfterLast("github.com/test/lancet", "/"))
|
||||||
assert.Equal("/lancet", AfterLast("github.com/test/lancet", "test"))
|
assert.Equal("/lancet", AfterLast("github.com/test/lancet", "test"))
|
||||||
assert.Equal("/lancet", AfterLast("github.com/test/test/lancet", "test"))
|
assert.Equal("/lancet", AfterLast("github.com/test/test/lancet", "test"))
|
||||||
@@ -465,3 +493,15 @@ func TestRemoveWhiteSpace(t *testing.T) {
|
|||||||
assert.Equal("helloworld", RemoveWhiteSpace(str, true))
|
assert.Equal("helloworld", RemoveWhiteSpace(str, true))
|
||||||
assert.Equal("hello world", RemoveWhiteSpace(str, false))
|
assert.Equal("hello world", RemoveWhiteSpace(str, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSubInBetween(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSubInBetween")
|
||||||
|
|
||||||
|
str := "abcde"
|
||||||
|
|
||||||
|
assert.Equal("", SubInBetween(str, "", ""))
|
||||||
|
assert.Equal("ab", SubInBetween(str, "", "c"))
|
||||||
|
assert.Equal("bc", SubInBetween(str, "a", "d"))
|
||||||
|
assert.Equal("", SubInBetween(str, "a", ""))
|
||||||
|
assert.Equal("", SubInBetween(str, "a", "f"))
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,18 +16,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
|
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
|
||||||
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
|
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
|
||||||
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
|
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]*)?$`)
|
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]$`)
|
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+)*`)
|
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}$`)
|
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]$`)
|
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]")
|
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
|
||||||
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
|
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})$`)
|
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})$`)
|
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)
|
||||||
@@ -362,3 +370,59 @@ func IsPrintable(str string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -448,3 +448,90 @@ func TestIsPrintable(t *testing.T) {
|
|||||||
assert.Equal(true, IsPrintable("😄"))
|
assert.Equal(true, IsPrintable("😄"))
|
||||||
assert.Equal(false, IsPrintable("\u0000"))
|
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