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

Compare commits

...

54 Commits

Author SHA1 Message Date
dudaodong
d910af24e0 release v1.4.3 2024-03-05 14:53:54 +08:00
dudaodong
5fc21330da feat: add new functions to mathutil package 2024-03-05 10:41:07 +08:00
dudaodong
928e3a390d feat: merge some new functions from rc branch 2024-03-04 16:36:20 +08:00
dudaodong
48519aba2b feat: add MapToStruct 2024-02-23 10:29:46 +08:00
dudaodong
97ea636e9e feat: add WriteMapsToCsv 2024-02-06 17:17:17 +08:00
dudaodong
f82f49a4c2 feat: add SubInBetween 2024-02-06 17:13:00 +08:00
dudaodong
0fc8733915 feat: add SubInBetween 2024-02-06 17:09:36 +08:00
dudaodong
44022c5861 refactor: refact Comma function 2024-02-06 17:09:08 +08:00
dudaodong
ec0222c5b1 refactor: refact Comma function 2024-02-06 17:06:06 +08:00
dudaodong
76b82a2fa1 release v1.4.2 2023-10-07 11:25:36 +08:00
dudaodong
d9dc2993b3 update readme file 2023-10-07 11:25:00 +08:00
dudaodong
ae42a9fdff Merge branch 'v1' of github.com:duke-git/lancet into v1 2023-09-24 19:19:30 +08:00
dudaodong
f37e55d9f1 feat: add ReadFile 2023-09-24 19:19:09 +08:00
dudaodong
d920a51988 add tempdir 2023-09-18 10:08:19 +08:00
dudaodong
561c42a24e feat: add rsa encrypt 2023-09-17 16:21:40 +08:00
dudaodong
12d74489d5 update doc 2023-09-17 16:12:12 +08:00
dudaodong
4959f26003 release v1.4.1 2023-07-31 16:44:44 +08:00
dudaodong
eb683a33d2 doc: update readme file 2023-07-29 16:57:57 +08:00
dudaodong
0e63489e9e doc: update readme file 2023-07-28 17:39:36 +08:00
dudaodong
d9e318550a feat: add new functions to datetime package 2023-07-28 17:25:13 +08:00
dudaodong
993b0e6023 feat: add Join 2023-07-27 20:14:57 +08:00
dudaodong
7cf358a0ec fix: fix CreateDir bug 2023-07-27 18:00:56 +08:00
dudaodong
b85545c584 refactor: clean code 2023-07-27 17:58:57 +08:00
dudaodong
c3c6c92cd4 refactor: clean code 2023-07-27 17:58:40 +08:00
dudaodong
8587abc977 feat: add base64 support for cryptor package 2023-07-27 17:54:26 +08:00
dudaodong
5c01b7e675 release v1.4.0 2023-06-20 10:24:17 +08:00
dudaodong
0247ac232a feat: add ZipAppendEntry 2023-06-20 10:23:12 +08:00
dudaodong
e77354d7ff feat: add File upload for HttpPost 2023-06-20 10:12:23 +08:00
dudaodong
8998dc35bb test: update TestToString 2023-06-15 14:45:12 +08:00
dudaodong
ad9fd196ce fix: fix bug of issue#112 (ToString precision lost when conver float32 and float64) 2023-06-15 14:40:30 +08:00
dudaodong
c8a65c33a4 format code 2023-06-13 15:09:31 +08:00
dudaodong
69a797f8ed doc: format code in doc file 2023-06-13 15:08:40 +08:00
dudaodong
1e5b69e9bf feat: add RemoveWhiteSpace 2023-06-13 15:06:27 +08:00
dudaodong
275abcc8c2 feat: add RandUniqueIntSlice 2023-06-13 15:03:45 +08:00
dudaodong
065b3b84fe add os_test.go 2023-06-13 15:00:40 +08:00
dudaodong
4bc43f3278 feat: add Log 2023-06-13 14:59:30 +08:00
dudaodong
f3382ceac9 feat: add WirteCsvFile 2023-06-13 14:56:43 +08:00
dudaodong
d20f8783b2 feat: add Utf8ToGbk and GbkToUtf8 2023-06-13 14:49:40 +08:00
dudaodong
8432a4e1ee test: update TestExecCommand 2023-06-03 18:33:16 +08:00
dudaodong
5a8ff17b52 release v1.3.9 2023-06-01 10:06:48 +08:00
dudaodong
6b46a0c05c feat: add WriteBytesToFile and WriteStringToFile 2023-05-31 17:36:12 +08:00
dudaodong
4b8b624b4c feat: add ContainsAll and ContainsAny 2023-05-31 17:27:25 +08:00
dudaodong
f274375e62 feat: add IsWeekend 2023-05-31 17:23:47 +08:00
dudaodong
6dc017a5fa feat: add BetweenSeconds and DayOfYear 2023-05-31 10:12:17 +08:00
dudaodong
e1fb97095d feat: add ReplaceWithMap, Trim, SplitAndTrim, HideString 2023-05-30 14:12:56 +08:00
dudaodong
d8f5a15590 feat: add AddYear and IsLeapYear 2023-05-30 14:07:11 +08:00
dudaodong
1202ac955d fix: fix timeFormat issue 2023-05-30 11:59:46 +08:00
dudaodong
84b2cec9b5 fix: fix PingConnected failed in win os 2023-05-30 11:58:29 +08:00
dudaodong
2d01a13787 feat: add ToInterface and CopyProperties 2023-05-30 11:54:57 +08:00
dudaodong
db9b045500 doc: add Cos, Sin, LCM, GCD function 2023-05-30 11:47:00 +08:00
dudaodong
2701bcc4d2 feat: add Cos, Sin, LCM, GCD function 2023-05-30 11:41:54 +08:00
dudaodong
b9745fd08b fix: comment TestMTime 2023-05-30 11:02:03 +08:00
dudaodong
3b1597d6f7 fix: fix body param bug when send post request 2023-05-30 11:01:39 +08:00
dudaodong
40ab5e8f7b release v1.3.8 2023-04-26 18:04:50 +08:00
64 changed files with 9306 additions and 1282 deletions

5
.gitignore vendored
View File

@@ -5,6 +5,9 @@ cryptor/*.txt
fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/tempdir
fileutil/unzip/*
slice/testdata/*
cryptor/*.pem
cryptor/*.pem
docs/node_modules
docs/.vitepress

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-v1.16-9cf)
[![Release](https://img.shields.io/badge/release-1.3.7-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-1.4.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com//duke-git/lancet?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -96,10 +96,18 @@ import "github.com/duke-git/lancet/convertor"
- [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)
- [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)
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DecodeByte)
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DeepClone)
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#CopyProperties)
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToInterface)
- [Utf8ToGbk](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#Utf8ToGbk)
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#GbkToUtf8)
- [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.
@@ -130,18 +138,30 @@ import "github.com/duke-git/lancet/cryptor"
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesOfbEncrypt)
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesOfbDecrypt)
- [HmacMd5](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacMd5)
- [HmacMd5WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacMd5WithBase64)
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha1)
- [HmacSha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha1WithBase64)
- [HmacSha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha256)
- [HmacSha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha256WithBase64)
- [HmacSha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha512)
- [HmacSha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha512WithBase64)
- [Md5String](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5String)
- [Md5StringWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5StringWithBase64)
- [Md5Byte](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5Byte)
- [Md5ByteWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5ByteWithBase64)
- [Md5File](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5File)
- [Sha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha1)
- [Sha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha1WithBase64)
- [Sha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha256)
- [Sha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha256WithBase64)
- [Sha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha512)
- [Sha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha512WithBase64)
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#GenerateRsaKey)
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaDecrypt)
- [GenerateRsaKeyPair](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#GenerateRsaKeyPair)
- [RsaEncryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaEncryptOAEP)
- [RsaDecryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaDecryptOAEP)
### 4. Datetime package supports date and time format and compare.
```go
@@ -153,6 +173,7 @@ import "github.com/duke-git/lancet/datetime"
- [AddDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddMinute)
- [AddYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddYear)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfDay)
@@ -180,6 +201,15 @@ import "github.com/duke-git/lancet/datetime"
- [ToFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToIso8601)
- [IsLeapYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#IsLeapYear)
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BetweenSeconds)
- [DayOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#DayOfYear)
- [IsWeekend](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#IsWeekend)
- [NowDateOrTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NowDateOrTime)
- [Timestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#Timestamp)
- [TimestampMilli](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#TimestampMilli)
- [TimestampMicro](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#TimestampMicro)
- [TimestampNano](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#TimestampNano)
### 5. Fileutil package implements some basic functions for file operations.
@@ -203,6 +233,7 @@ import "github.com/duke-git/lancet/fileutil"
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileToString)
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileByLine)
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Zip)
- [ZipAppendEntry](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ZipAppendEntry)
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#UnZip)
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CurrentPath)
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsZipFile)
@@ -210,6 +241,11 @@ import "github.com/duke-git/lancet/fileutil"
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#MTime)
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Sha)
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadCsvFile)
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteCsvFile)
- [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)
- [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.
@@ -260,10 +296,19 @@ import "github.com/duke-git/lancet/mathutil"
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RoundToFloat)
- [RoundToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RoundToString)
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#TruncRound)
- [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)
- [RadianToAngle](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RadianToAngle)
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#PointDistance)
- [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#IsPrime)
- [GCD](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#GCD)
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#LCM)
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Cos)
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Sin)
- [Log](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Log)
### 9. Netutil package contains functions to get net information and send http request.
@@ -309,6 +354,7 @@ import "github.com/duke-git/lancet/random"
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeral)
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeralOrLetter)
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
- [RandUniqueIntSlice](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUniqueIntSlice)
### 11. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
@@ -372,6 +418,7 @@ import "github.com/duke-git/lancet/slice"
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Union)
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#UpdateByIndex)
- [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Without)
- [Join](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Join)
### 13. Strutil package contains some functions to manipulate string.
@@ -387,6 +434,8 @@ import "github.com/duke-git/lancet/strutil"
- [BeforeLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Capitalize)
- [ContainsAll](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ContainsAll)
- [ContainsAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ContainsAny)
- [IsString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#KebabCase)
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperKebabCase)
@@ -410,6 +459,14 @@ import "github.com/duke-git/lancet/strutil"
- [HasPrefixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HasPrefixAny)
- [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HasSuffixAny)
- [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IndexOffset)
- [ReplaceWithMap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ReplaceWithMap)
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Trim)
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitAndTrim)
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HideString)
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#RemoveWhiteSpace)
- [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.
@@ -470,6 +527,16 @@ import "github.com/duke-git/lancet/validator"
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsGBK)
- [IsASCII](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsASCII)
- [IsPrintable](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsPrintable)
- [IsBin](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsBin)
- [IsHex](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsHex)
- [IsBase64URL](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsBase64URL)
- [IsJWT](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsJWT)
- [IsVisa](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsVisa)
- [IsMasterCard](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsMasterCard)
- [IsAmericanExpress](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAmericanExpress)
- [IsUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsUnionPay)
- [IsChinaUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChinaUnionPay)
## How to Contribute

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-v1.16-9cf)
[![Release](https://img.shields.io/badge/release-1.3.7-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-1.4.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com//duke-git/lancet?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -95,10 +95,19 @@ import "github.com/duke-git/lancet/convertor"
- [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)
- [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)
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DecodeByte)
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DeepClone)
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#CopyProperties)
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInterface)
- [Utf8ToGbk](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#Utf8ToGbk)
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#GbkToUtf8)
- [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 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。
@@ -129,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)
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbDecrypt)
- [HmacMd5](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacMd5)
- [HmacMd5WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacMd5WithBase64)
md#HmacSha256WithBase64)
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha1)
- [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)
- [HmacSha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha512WithBase64)
- [Md5String](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5String)
- [Md5StringWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5StringWithBase64)
- [Md5Byte](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5Byte)
- [Md5ByteWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5ByteWithBase64)
- [Md5File](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5File)
- [Sha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha1)
- [Sha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha1WithBase64)
- [Sha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha256)
- [Sha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha256WithBase64)
- [Sha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha512)
- [Sha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha512WithBase64)
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#GenerateRsaKey)
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecrypt)
- [GenerateRsaKeyPair](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#GenerateRsaKeyPair)
- [RsaEncryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncryptOAEP)
- [RsaDecryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecryptOAEP)
### 4. datetime 日期时间处理包,格式化日期,比较日期。
@@ -152,6 +176,7 @@ import "github.com/duke-git/lancet/datetime"
- [AddDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddMinute)
- [AddYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddYear)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfDay)
@@ -179,6 +204,15 @@ import "github.com/duke-git/lancet/datetime"
- [ToFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToIso8601)
- [IsLeapYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsLeapYear)
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#BetweenSeconds)
- [DayOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#DayOfYear)
- [IsWeekend](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsWeekend)
- [NowDateOrTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NowDateOrTime)
- [Timestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#Timestamp)
- [TimestampMilli](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampMilli)
- [TimestampMicro](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampMicro)
- [TimestampNano](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampNano)
### 5. fileutil 包支持文件基本操作。
@@ -202,6 +236,7 @@ import "github.com/duke-git/lancet/fileutil"
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileToString)
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileByLine)
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Zip)
- [ZipAppendEntry](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ZipAppendEntry)
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#UnZip)
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CurrentPath)
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsZipFile)
@@ -209,6 +244,11 @@ import "github.com/duke-git/lancet/fileutil"
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MTime)
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Sha)
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadCsvFile)
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteCsvFile)
- [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)
- [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 格式化器包含一些数据格式化处理方法。
@@ -259,11 +299,19 @@ import "github.com/duke-git/lancet/mathutil"
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToFloat)
- [RoundToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToString)
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#TruncRound)
- [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)
- [RadianToAngle](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RadianToAngle)
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#PointDistance)
- [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#IsPrime)
- [GCD](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#GCD)
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#LCM)
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Cos)
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Sin)
- [Log](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Log)
### 9. netutil 网络包支持获取 ip 地址,发送 http 请求。
```go
@@ -308,6 +356,7 @@ import "github.com/duke-git/lancet/random"
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeral)
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeralOrLetter)
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
- [RandUniqueIntSlice](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUniqueIntSlice)
### 11. retry 重试执行函数直到函数运行成功或被 context cancel。
@@ -371,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)
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UpdateByIndex)
- [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Without)
- [Join](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Join)
### 13. strutil 包含处理字符串的相关函数。
@@ -386,6 +436,8 @@ import "github.com/duke-git/lancet/strutil"
- [BeforeLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Capitalize)
- [ContainsAll](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAll)
- [ContainsAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAny)
- [IsString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#KebabCase)
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperKebabCase)
@@ -409,6 +461,13 @@ import "github.com/duke-git/lancet/strutil"
- [HasPrefixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasPrefixAny)
- [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasSuffixAny)
- [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IndexOffset)
- [ReplaceWithMap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ReplaceWithMap)
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Trim)
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitAndTrim)
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HideString)
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveWhiteSpace)
- [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 相关函数。
@@ -469,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)
- [IsASCII](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsASCII)
- [IsPrintable](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsPrintable)
- [IsBin](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBin)
- [IsHex](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsHex)
- [IsBase64URL](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBase64URL)
- [IsJWT](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsJWT)
- [IsVisa](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsVisa)
- [IsMasterCard](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsMasterCard)
- [IsAmericanExpress](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAmericanExpress)
- [IsUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsUnionPay)
- [IsChinaUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChinaUnionPay)
## 如何贡献代码

View File

@@ -6,16 +6,21 @@ package convertor
import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"io"
"math"
"reflect"
"regexp"
"strconv"
"strings"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
// ToBool convert string to a boolean
@@ -78,33 +83,45 @@ func ToChar(s string) []string {
// ToString convert value to string
func ToString(value interface{}) string {
res := ""
if value == nil {
return res
return ""
}
v := reflect.ValueOf(value)
switch value.(type) {
case float32, float64:
res = strconv.FormatFloat(v.Float(), 'f', -1, 64)
return res
case int, int8, int16, int32, int64:
res = strconv.FormatInt(v.Int(), 10)
return res
case uint, uint8, uint16, uint32, uint64:
res = strconv.FormatUint(v.Uint(), 10)
return res
switch val := value.(type) {
case float32:
return strconv.FormatFloat(float64(val), 'f', -1, 32)
case float64:
return strconv.FormatFloat(val, 'f', -1, 64)
case int:
return strconv.FormatInt(int64(val), 10)
case int8:
return strconv.FormatInt(int64(val), 10)
case int16:
return strconv.FormatInt(int64(val), 10)
case int32:
return strconv.FormatInt(int64(val), 10)
case int64:
return strconv.FormatInt(val, 10)
case uint:
return strconv.FormatUint(uint64(val), 10)
case uint8:
return strconv.FormatUint(uint64(val), 10)
case uint16:
return strconv.FormatUint(uint64(val), 10)
case uint32:
return strconv.FormatUint(uint64(val), 10)
case uint64:
return strconv.FormatUint(val, 10)
case string:
res = v.String()
return res
return val
case []byte:
res = string(v.Bytes())
return res
return string(val)
default:
newValue, _ := json.Marshal(value)
res = string(newValue)
return res
b, err := json.Marshal(val)
if err != nil {
return ""
}
return string(b)
}
}
@@ -279,43 +296,166 @@ func DeepClone(src interface{}) 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)
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
func CopyProperties(dst, src interface{}) error {
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
return errors.New("CopyProperties: param dst should be struct pointer")
return errors.New("CopyProperties: parameter dst should be struct pointer")
}
if srcType.Kind() == reflect.Ptr {
srcType, srcValue = srcType.Elem(), srcValue.Elem()
srcType = srcType.Elem()
}
if srcType.Kind() != reflect.Struct {
return errors.New("CopyProperties: param src should be a struct or struct pointer")
return errors.New("CopyProperties: parameter src should be a struct or struct pointer")
}
dstType, dstValue = dstType.Elem(), dstValue.Elem()
bytes, err := json.Marshal(src)
if err != nil {
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
}
err = json.Unmarshal(bytes, dst)
if err != nil {
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
}
propertyNums := dstType.NumField()
return nil
}
for i := 0; i < propertyNums; i++ {
property := dstType.Field(i)
propertyValue := srcValue.FieldByName(property.Name)
// ToInterface converts reflect value to its interface type.
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
if v.IsValid() && v.CanInterface() {
return v.Interface(), true
}
switch v.Kind() {
case reflect.Bool:
return v.Bool(), true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int(), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint(), true
case reflect.Float32, reflect.Float64:
return v.Float(), true
case reflect.Complex64, reflect.Complex128:
return v.Complex(), true
case reflect.String:
return v.String(), true
case reflect.Ptr:
return ToInterface(v.Elem())
case reflect.Interface:
return ToInterface(v.Elem())
default:
return nil, false
}
}
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
continue
}
// Utf8ToGbk convert utf8 encoding data to GBK encoding data.
func Utf8ToGbk(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
b, err := io.ReadAll(r)
return b, err
}
if dstValue.Field(i).CanSet() {
dstValue.Field(i).Set(propertyValue)
// GbkToUtf8 convert GBK encoding data to utf8 encoding data.
func GbkToUtf8(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
b, err := io.ReadAll(r)
return b, err
}
// 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)
}
}

View File

@@ -4,7 +4,10 @@
// Package convertor implements some functions to convert data.
package convertor
import "reflect"
import (
"fmt"
"reflect"
)
type cloner struct {
ptrs map[reflect.Type]map[uintptr]reflect.Value
@@ -214,3 +217,70 @@ func (c *cloner) cloneStruct(v reflect.Value) reflect.Value {
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 ""
}

View File

@@ -1,11 +1,17 @@
package convertor
import (
"encoding/base64"
"errors"
"fmt"
"io"
"reflect"
"testing"
"unicode/utf8"
"unsafe"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/validator"
)
func TestToChar(t *testing.T) {
@@ -119,7 +125,7 @@ func TestToString(t *testing.T) {
"", "",
"0", "1", "-1",
"123", "123", "123", "123", "123", "123", "123",
"12.3", "12.300000190734863",
"12.3", "12.3",
"true", "false",
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
@@ -262,49 +268,415 @@ func TestDeepClone(t *testing.T) {
func TestCopyProperties(t *testing.T) {
assert := internal.NewAssert(t, "TestCopyProperties")
type Address struct {
Country string
ZipCode string
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type User struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Employee struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
employee1 := Employee{}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
err := CopyProperties(&employee1, &user)
indicatorVO := IndicatorVO{}
err := CopyProperties(&indicatorVO, indicator)
assert.IsNil(err)
assert.Equal("user001", employee1.Name)
assert.Equal("Admin", employee1.Role)
assert.Equal("CN", employee1.Addr.Country)
assert.Equal(0, employee1.salary)
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
err = CopyProperties(&employee2, &user)
assert.IsNil(err)
assert.Equal("user001", employee2.Name)
assert.Equal("Admin", employee2.Role)
assert.Equal("CN", employee2.Addr.Country)
assert.Equal(500, employee2.salary)
assert.Equal("001", indicatorVO.Id)
assert.Equal("127.0.0.1", indicatorVO.Ip)
assert.Equal(3, len(indicatorVO.Disk))
}
func TestToInterface(t *testing.T) {
assert := internal.NewAssert(t, "TestToInterface")
cases := []reflect.Value{
reflect.ValueOf("abc"),
reflect.ValueOf(int(0)), reflect.ValueOf(int8(1)), reflect.ValueOf(int16(-1)), reflect.ValueOf(int32(123)), reflect.ValueOf(int64(123)),
reflect.ValueOf(uint(123)), reflect.ValueOf(uint8(123)), reflect.ValueOf(uint16(123)), reflect.ValueOf(uint32(123)), reflect.ValueOf(uint64(123)),
reflect.ValueOf(float64(12.3)), reflect.ValueOf(float32(12.3)),
reflect.ValueOf(true), reflect.ValueOf(false),
}
expected := []interface{}{
"abc",
0, int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float64(12.3), float32(12.3),
true, false,
}
for i := 0; i < len(cases); i++ {
actual, _ := ToInterface(cases[i])
assert.Equal(expected[i], actual)
}
nilVal, ok := ToInterface(reflect.ValueOf(nil))
assert.EqualValues(nil, nilVal)
assert.Equal(false, ok)
}
func TestUtf8ToGbk(t *testing.T) {
assert := internal.NewAssert(t, "TestUtf8ToGbk")
utf8Data := []byte("hello")
gbkData, err := Utf8ToGbk(utf8Data)
assert.Equal(true, utf8.Valid(utf8Data))
assert.Equal(true, validator.IsGBK(gbkData))
assert.IsNil(err)
}
func TestGbkToUtf8(t *testing.T) {
assert := internal.NewAssert(t, "TestGbkToUtf8")
gbkData, err := Utf8ToGbk([]byte("hello"))
utf8Data, err := GbkToUtf8(gbkData)
assert.IsNil(err)
assert.Equal(true, utf8.Valid(utf8Data))
assert.Equal("hello", string(utf8Data))
}
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))
}

View File

@@ -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
}

View File

@@ -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))
}

View File

@@ -37,6 +37,27 @@ func Md5String(s string) string {
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
func Md5File(filename string) (string, error) {
if fileInfo, err := os.Stat(filename); err != nil {
@@ -76,6 +97,13 @@ func HmacMd5(data, key string) string {
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
func HmacSha1(data, key string) string {
h := hmac.New(sha1.New, []byte(key))
@@ -83,6 +111,13 @@ func HmacSha1(data, key string) string {
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
func HmacSha256(data, key string) string {
h := hmac.New(sha256.New, []byte(key))
@@ -90,6 +125,13 @@ func HmacSha256(data, key string) string {
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
func HmacSha512(data, key string) string {
h := hmac.New(sha512.New, []byte(key))
@@ -97,6 +139,13 @@ func HmacSha512(data, key string) string {
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
func Sha1(data string) string {
sha1 := sha1.New()
@@ -104,6 +153,13 @@ func Sha1(data string) string {
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
func Sha256(data string) string {
sha256 := sha256.New()
@@ -111,9 +167,23 @@ func Sha256(data string) string {
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
func Sha512(data string) string {
sha512 := sha512.New()
sha512.Write([]byte(data))
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("")))
}

View File

@@ -21,6 +21,22 @@ func TestMd5String(t *testing.T) {
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) {
fileMd5, err := Md5File("./basic.go")
assert := internal.NewAssert(t, "TestMd5File")
@@ -33,6 +49,11 @@ func TestHmacMd5(t *testing.T) {
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) {
s := "hello world"
key := "12345"
@@ -43,6 +64,16 @@ func TestHmacSha1(t *testing.T) {
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) {
s := "hello world"
key := "12345"
@@ -53,6 +84,16 @@ func TestHmacSha256(t *testing.T) {
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) {
s := "hello world"
key := "12345"
@@ -63,6 +104,16 @@ func TestHmacSha512(t *testing.T) {
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) {
s := "hello world"
sha1 := Sha1(s)
@@ -72,6 +123,14 @@ func TestSha1(t *testing.T) {
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) {
s := "hello world"
sha256 := Sha256(s)
@@ -81,6 +140,14 @@ func TestSha256(t *testing.T) {
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) {
s := "hello world"
sha512 := Sha512(s)
@@ -89,3 +156,11 @@ func TestSha512(t *testing.T) {
assert := internal.NewAssert(t, "TestSha512")
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
View 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
View 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))
}

View File

@@ -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
}

View File

@@ -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))
}

View File

@@ -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
}

View File

@@ -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))
}

View File

@@ -3,29 +3,35 @@
// Package datetime implements some functions to format date and time.
// Note:
// 1. `format` param in FormatTimeToStr function should be as flow:
//"yyyy-mm-dd hh:mm:ss"
//"yyyy-mm-dd hh:mm"
//"yyyy-mm-dd hh"
//"yyyy-mm-dd"
//"yyyy-mm"
//"mm-dd"
//"dd-mm-yy hh:mm:ss"
//"yyyy/mm/dd hh:mm:ss"
//"yyyy/mm/dd hh:mm"
//"yyyy/mm/dd hh"
//"yyyy/mm/dd"
//"yyyy/mm"
//"mm/dd"
//"dd/mm/yy hh:mm:ss"
//"yyyy"
//"mm"
//"hh:mm:ss"
//"mm:ss"
// 1. `format` param in FormatTimeToStr function should be as flow (case no sensitive):
// "yyyy-mm-dd hh:mm:ss"
// "yyyy-mm-dd hh:mm"
// "yyyy-mm-dd hh"
// "yyyy-mm-dd"
// "yyyy-mm"
// "mm-dd"
// "dd-mm-yy hh:mm:ss"
// "yyyy/mm/dd hh:mm:ss"
// "yyyy/mm/dd hh:mm"
// "yyyy/mm/dd hh"
// "yyyy/mm/dd"
// "yyyy/mm"
// "mm/dd"
// "dd/mm/yy hh:mm:ss"
// "yyyymmdd"
// "mmddyy"
// "yyyy"
// "yy"
// "mm"
// "hh:mm:ss"
// "hh:mm"
// "mm:ss"
package datetime
import (
"fmt"
"strings"
"time"
)
@@ -35,7 +41,7 @@ func init() {
timeFormat = map[string]string{
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
"yyyy-mm-dd hh": "2006-01-02 15:04",
"yyyy-mm-dd hh": "2006-01-02 15",
"yyyy-mm-dd": "2006-01-02",
"yyyy-mm": "2006-01",
"mm-dd": "01-02",
@@ -47,9 +53,13 @@ func init() {
"yyyy/mm": "2006/01",
"mm/dd": "01/02",
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
"yyyymmdd": "20060102",
"mmddyy": "010206",
"yyyy": "2006",
"yy": "06",
"mm": "01",
"hh:mm:ss": "15:04:05",
"hh:mm": "15:04",
"mm:ss": "04:05",
}
}
@@ -69,6 +79,11 @@ func AddDay(t time.Time, day int64) time.Time {
return t.Add(24 * time.Hour * time.Duration(day))
}
// AddYear add or sub year to the time.
func AddYear(t time.Time, year int64) time.Time {
return t.Add(365 * 24 * time.Hour * time.Duration(year))
}
// GetNowDate return format yyyy-mm-dd of current date
func GetNowDate() string {
return time.Now().Format("2006-01-02")
@@ -97,18 +112,39 @@ func GetNightTimestamp() int64 {
}
// FormatTimeToStr convert time to string
func FormatTimeToStr(t time.Time, format string) string {
return t.Format(timeFormat[format])
func FormatTimeToStr(t time.Time, 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 t.In(loc).Format(tf)
}
return t.Format(tf)
}
// FormatStrToTime convert string to time
func FormatStrToTime(str, format string) (time.Time, error) {
v, ok := timeFormat[format]
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error) {
tf, ok := timeFormat[strings.ToLower(format)]
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
@@ -180,3 +216,108 @@ func BeginOfYear(t time.Time) time.Time {
func EndOfYear(t time.Time) time.Time {
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
}
// IsLeapYear check if param year is leap year or not.
func IsLeapYear(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
// BetweenSeconds returns the number of seconds between two times.
func BetweenSeconds(t1 time.Time, t2 time.Time) int64 {
index := t2.Unix() - t1.Unix()
return index
}
// DayOfYear returns which day of the year the parameter date `t` is.
func DayOfYear(t time.Time) int {
y, m, d := t.Date()
firstDay := time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
nowDate := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
return int(nowDate.Sub(firstDay).Hours() / 24)
}
// IsWeekend checks if passed time is weekend or not.
func IsWeekend(t time.Time) bool {
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
}
// NowDateOrTime return current datetime with specific format and timezone.
func NowDateOrTime(format string, timezone ...string) string {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return ""
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return ""
}
return time.Now().In(loc).Format(tf)
}
return time.Now().Format(tf)
}
// Timestamp return current second timestamp.
func Timestamp(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.Unix()
}
// TimestampMilli return current mill second timestamp.
func TimestampMilli(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
}
// TimestampMicro return current micro second timestamp.
func TimestampMicro(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
}
// TimestampNano return current nano second timestamp.
func TimestampNano(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.UnixNano()
}

View File

@@ -46,6 +46,19 @@ func TestAddMinute(t *testing.T) {
assert.Equal(float64(-2), diff2.Minutes())
}
func TestAddYear(t *testing.T) {
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
after2Years := AddYear(now, 1)
diff1 := after2Years.Sub(now)
assert.Equal(float64(8760), diff1.Hours())
before2Years := AddYear(now, -1)
diff2 := before2Years.Sub(now)
assert.Equal(float64(-8760), diff2.Hours())
}
func TestGetNowDate(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNowDate")
expected := time.Now().Format("2006-01-02")
@@ -231,3 +244,92 @@ func TestEndOfYear(t *testing.T) {
assert.Equal(expected, actual)
}
func TestIsLeapYear(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfYear")
result1 := IsLeapYear(2000)
result2 := IsLeapYear(2001)
assert.Equal(true, result1)
assert.Equal(false, result2)
}
func TestBetweenSeconds(t *testing.T) {
assert := internal.NewAssert(t, "TestBetweenSeconds")
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := BetweenSeconds(today, tomorrow)
result2 := BetweenSeconds(today, yesterday)
assert.Equal(int64(86400), result1)
assert.Equal(int64(-86400), result2)
}
func TestDayOfYear(t *testing.T) {
assert := internal.NewAssert(t, "TestDayOfYear")
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := DayOfYear(date1)
assert.Equal(31, result1)
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
result2 := DayOfYear(date2)
assert.Equal(1, result2)
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
result3 := DayOfYear(date3)
assert.Equal(0, result3)
}
func TestIsWeekend(t *testing.T) {
assert := internal.NewAssert(t, "TestIsWeekend")
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
result := IsWeekend(date)
assert.Equal(true, result)
date1 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
result1 := IsWeekend(date1)
assert.Equal(true, result1)
date2 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
result2 := IsWeekend(date2)
assert.Equal(false, result2)
}
func TestNowDateOrTime(t *testing.T) {
t.Parallel()
formats := []string{
"yyyy-mm-dd hh:mm:ss",
"yyyy-mm-dd",
"dd-mm-yy hh:mm:ss",
"yyyy/mm/dd hh:mm:ss",
"hh:mm:ss",
"yyyy/mm",
"yyyy-mm-dd hh",
}
for i := 0; i < len(formats); i++ {
result := NowDateOrTime(formats[i], "UTC")
t.Log(result)
}
}
func TestTimestamp(t *testing.T) {
t.Parallel()
ts1 := Timestamp()
t.Log(ts1)
ts2 := TimestampMilli()
t.Log(ts2)
ts3 := TimestampMicro()
t.Log(ts3)
ts4 := TimestampNano()
t.Log(ts4)
}

View File

@@ -33,9 +33,19 @@ import (
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToStruct](#MapToStruct)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
- [ToInterface](#ToInterface)
- [Utf8ToGbk](#Utf8ToGbk)
- [GbkToUtf8](#GbkToUtf8)
- [ToStdBase64](#ToStdBase64)
- [ToUrlBase64](#ToUrlBase64)
- [ToRawStdBase64](#ToRawStdBase64)
- [ToRawUrlBase64](#ToRawUrlBase64)
<div STYLE="page-break-after: always;"></div>
@@ -351,7 +361,7 @@ func main() {
### <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>
@@ -384,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>
<p>Encode data to byte slice.</p>
@@ -501,3 +564,453 @@ func main() {
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>Copies each field from the source struct into the destination struct. Use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.</p>
<b>Signature:</b>
```go
func CopyProperties(dst, src interface{}) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := convertor.CopyProperties(&indicatorVO, indicator)
if err != nil {
return
}
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
```
### <span id="ToInterface">ToInterface</span>
<p>Converts reflect value to its interface type.</p>
<b>Signature:</b>
```go
func ToInterface(v reflect.Value) (value interface{}, ok bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
val := reflect.ValueOf("abc")
iVal, ok := convertor.ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
```
### <span id="Utf8ToGbk">Utf8ToGbk</span>
<p>Converts utf8 encoding data to GBK encoding data.</p>
<b>Signature:</b>
```go
func Utf8ToGbk(bs []byte) ([]byte, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/validator"
)
func main() {
utf8Data := []byte("hello")
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(validator.IsGBK(gbkData))
// Output:
// true
// true
}
```
### <span id="GbkToUtf8">GbkToUtf8</span>
<p>Converts GBK encoding data to utf8 encoding data.</p>
<b>Signature:</b>
```go
func GbkToUtf8(bs []byte) ([]byte, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
utf8Data, _ := convertor.GbkToUtf8(gbkData)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(string(utf8Data))
// Output:
// true
// hello
}
```
### <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
}
```

View File

@@ -33,9 +33,18 @@ import (
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToStruct](#MapToStruct)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
- [ToInterface](#ToInterface)
- [Utf8ToGbk](#Utf8ToGbk)
- [GbkToUtf8](#GbkToUtf8)
- [ToStdBase64](#ToStdBase64)
- [ToUrlBase64](#ToUrlBase64)
- [ToRawStdBase64](#ToRawStdBase64)
- [ToRawUrlBase64](#ToRawUrlBase64)
<div STYLE="page-break-after: always;"></div>
@@ -384,6 +393,59 @@ func main() {
}
```
### <span id="MapToStruct">MapToStruct</span>
<p>将map转成structstruct中导出字段需要设置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>
<p>将data编码成字节切片</p>
@@ -501,3 +563,454 @@ func main() {
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化需要设置dst和src struct字段的json tag。</p>
<b>函数签名:</b>
```go
func CopyProperties(dst, src interface{}) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := convertor.CopyProperties(&indicatorVO, indicator)
if err != nil {
return
}
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
```
### <span id="ToInterface">ToInterface</span>
<p>将反射值转换成对应的interface类型。</p>
<b>函数签名:</b>
```go
func ToInterface(v reflect.Value) (value interface{}, ok bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
val := reflect.ValueOf("abc")
iVal, ok := convertor.ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
```
### <span id="Utf8ToGbk">Utf8ToGbk</span>
<p>utf8编码转GBK编码。</p>
<b>函数签名:</b>
```go
func Utf8ToGbk(bs []byte) ([]byte, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/validator"
)
func main() {
utf8Data := []byte("hello")
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(validator.IsGBK(gbkData))
// Output:
// true
// true
}
```
### <span id="GbkToUtf8">GbkToUtf8</span>
<p>GBK编码转utf8编码。</p>
<b>函数签名:</b>
```go
func GbkToUtf8(bs []byte) ([]byte, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
utf8Data, _ := convertor.GbkToUtf8(gbkData)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(string(utf8Data))
// Output:
// true
// hello
}
```
### <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
}
```

View File

@@ -6,10 +6,8 @@ Package cryptor contains some functions for data encryption and decryption. Supp
## 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/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>
@@ -46,17 +44,30 @@ import (
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacMd5WithBase64](#HmacMd5WithBase64)
- [HmacSha1](#HmacSha1)
- [HmacSha1WithBase64](#HmacSha1WithBase64)
- [HmacSha256](#HmacSha256)
- [HmacSha256WithBase64](#HmacSha256WithBase64)
- [HmacSha512](#HmacSha512)
- [HmacSha512WithBase64](#HmacSha512WithBase64)
- [Md5String](#Md5String)
- [Md5StringWithBase64](#Md5StringWithBase64)
- [Md5Byte](#Md5Byte)
- [Md5ByteWithBase64](#Md5ByteWithBase64)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha1WithBase64](#Sha1WithBase64)
- [Sha256](#Sha256)
- [Sha256WithBase64](#Sha256WithBase64)
- [Sha512](#Sha512)
- [Sha512WithBase64](#Sha512WithBase64)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
- [RsaEncryptOAEP](#RsaEncryptOAEP)
- [RsaDecryptOAEP](#RsaDecryptOAEP)
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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
}
```
### <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
}
```

View File

@@ -6,10 +6,8 @@ cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 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/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>
@@ -47,16 +45,28 @@ import (
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacSha1](#HmacSha1)
- [HmacSha1WithBase64](#HmacSha1WithBase64)
- [HmacSha256](#HmacSha256)
- [HmacSha256WithBase64](#HmacSha256WithBase64)
- [HmacSha512](#HmacSha512)
- [HmacSha512WithBase64](#HmacSha512WithBase64)
- [Md5String](#Md5String)
- [Md5StringWithBase64](#Md5StringWithBase64)
- [Md5Byte](#Md5Byte)
- [Md5ByteWithBase64](#Md5ByteWithBase64)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha1WithBase64](#Sha1WithBase64)
- [Sha256](#Sha256)
- [Sha256WithBase64](#Sha256WithBase64)
- [Sha512](#Sha512)
- [Sha512WithBase64](#Sha512WithBase64)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
- [RsaEncryptOAEP](#RsaEncryptOAEP)
- [RsaDecryptOAEP](#RsaDecryptOAEP)
<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>
<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>
```go
func HmacSha256(data, key string) string
func HmacSha1WithBase64(str, key string) string
```
<b>列子:</b>
<b>实例:</b>
```go
package main
@@ -710,22 +746,92 @@ import (
)
func main() {
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
str := "hello"
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>
<p>获取字符串sha512 hmac值</p>
<p>获取字符串sha512 hmac值</p>
<b>函数签名:</b>
```go
func HmacSha512(data, key string) string
func HmacSha512(str, key string) string
```
<b>列子:</b>
<b>示例:</b>
```go
package main
@@ -736,23 +842,60 @@ import (
)
func main() {
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
str := "hello"
key := "12345"
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>
<p>获取字符串md5值</p>
<p>获取字符串md5值</p>
<b>函数签名:</b>
```go
func Md5String(s string) string
func Md5String(str string) string
```
<b>列子:</b>
<b>示例:</b>
```go
package main
@@ -763,14 +906,106 @@ import (
)
func main() {
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
str := "hello"
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>
<p>获取文件md5值.</p>
<p>获取文件md5值</p>
<b>函数签名:</b>
@@ -778,7 +1013,7 @@ func main() {
func Md5File(filepath string) (string, error)
```
<b>列子:</b>
<b>示例:</b>
```go
package main
@@ -796,15 +1031,15 @@ func main() {
### <span id="Sha1">Sha1</span>
<p>获取字符串sha1值</p>
<p>获取字符串sha1值</p>
<b>函数签名:</b>
```go
func Sha1(data string) string
func Sha1(str string) string
```
<b>列子:</b>
<b>示例:</b>
```go
package main
@@ -815,22 +1050,56 @@ import (
)
func main() {
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
str := "hello"
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>
<p>获取字符串sha256值</p>
<p>获取字符串sha256值</p>
<b>函数签名:</b>
```go
func Sha256(data string) string
func Sha256(str string) string
```
<b>列子:</b>
<b>示例:</b>
```go
package main
@@ -841,22 +1110,56 @@ import (
)
func main() {
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
str := "hello"
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>
<p>获取字符串sha512值</p>
<p>获取字符串sha512值</p>
<b>函数签名:</b>
```go
func Sha512(data string) string
func Sha512(str string) string
```
<b>列子:</b>
<b>示例:</b>
```go
package main
@@ -867,8 +1170,42 @@ import (
)
func main() {
s := cryptor.Sha512("hello world"))
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
str := "hello"
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 {
fmt.Println(err)
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
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
}
```

View File

@@ -25,6 +25,7 @@ import (
- [AddDay](#AddDay)
- [AddHour](#AddHour)
- [AddMinute](#AddMinute)
- [AddYear](#AddYear)
- [BeginOfMinute](#BeginOfMinute)
- [BeginOfHour](#BeginOfHour)
- [BeginOfDay](#BeginOfDay)
@@ -52,6 +53,15 @@ import (
- [ToFormat](#ToFormat)
- [ToFormatForTpl](#ToFormatForTpl)
- [ToIso8601](#ToIso8601)
- [IsLeapYear](#IsLeapYear)
- [BetweenSeconds](#BetweenSeconds)
- [DayOfYear](#DayOfYear)
- [IsWeekend](#IsWeekend)
- [NowDateOrTime](#NowDateOrTime)
- [Timestamp](#Timestamp)
- [TimestampMilli](#TimestampMilli)
- [TimestampMicro](#TimestampMicro)
- [TimestampNano](#TimestampNano)
<div STYLE="page-break-after: always;"></div>
@@ -59,7 +69,7 @@ import (
## 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
@@ -70,14 +80,18 @@ import (
- dd-mm-yy hh:mm:ss
- yyyy/mm/dd hh:mm:ss
- yyyy/mm/dd hh:mm
- yyyy-mm-dd hh
- yyyy/mm/dd hh
- yyyy/mm/dd
- yyyy/mm
- mm/dd
- dd/mm/yy hh:mm:ss
- yyyymmdd
- mmddyy
- yyyy
- yy
- mm
- hh:mm:ss
- hh:mm
- mm:ss
### <span id="AddDay">AddDay</span>
@@ -170,6 +184,45 @@ func main() {
}
```
### <span id="AddYear">AddYear</span>
<p>Add or sub year to the time.</p>
<b>Signature:</b>
```go
func AddYear(t time.Time, year int64) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/datetime"
)
func main() {
now := time.Now()
after1Year := datetime.AddYear(now, 1)
diff1 := after1Year.Sub(now)
before1Year := datetime.AddYear(now, -1)
diff2 := before1Year.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 8760h0m0s
// -8760h0m0s
}
```
### <span id="BeginOfMinute">BeginOfMinute</span>
<p>Return beginning minute time of day.</p>
@@ -921,3 +974,389 @@ func main() {
fmt.Println(ts) //"2006-01-02T23:04:05+08:00"
}
```
### <span id="IsLeapYear">IsLeapYear</span>
<p>check if param `year` is leap year or not.</p>
<b>Signature:</b>
```go
func IsLeapYear(year int) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
result1 := datetime.IsLeapYear(2000)
result2 := datetime.IsLeapYear(2001)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="BetweenSeconds">BetweenSeconds</span>
<p>Return the number of seconds between two times.</p>
<b>Signature:</b>
```go
func BetweenSeconds(t1 time.Time, t2 time.Time) int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := datetime.BetweenSeconds(today, tomorrow)
result2 := datetime.BetweenSeconds(today, yesterday)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 86400
// -86400
}
```
### <span id="DayOfYear">DayOfYear</span>
<p>Returns which day of the year the parameter date `t` is.</p>
<b>Signature:</b>
```go
func DayOfYear(t time.Time) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := datetime.DayOfYear(date1)
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
result2 := datetime.DayOfYear(date2)
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
result3 := datetime.DayOfYear(date3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 31
// 1
// 0
}
```
### <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="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="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
}
```

View File

@@ -25,6 +25,7 @@ import (
- [AddDay](#AddDay)
- [AddHour](#AddHour)
- [AddMinute](#AddMinute)
- [AddYear](#AddYear)
- [BeginOfMinute](#BeginOfMinute)
- [BeginOfHour](#BeginOfHour)
- [BeginOfDay](#BeginOfDay)
@@ -52,6 +53,15 @@ import (
- [ToFormat](#ToFormat)
- [ToFormatForTpl](#ToFormatForTpl)
- [ToIso8601](#ToIso8601)
- [IsLeapYear](#IsLeapYear)
- [BetweenSeconds](#BetweenSeconds)
- [DayOfYear](#DayOfYear)
- [IsWeekend](#IsWeekend)
- [NowDateOrTime](#NowDateOrTime)
- [Timestamp](#Timestamp)
- [TimestampMilli](#TimestampMilli)
- [TimestampMicro](#TimestampMicro)
- [TimestampNano](#TimestampNano)
<div STYLE="page-break-after: always;"></div>
@@ -59,7 +69,7 @@ import (
## 注:
1. 方法 FormatTimeToStr 和 FormatStrToTime 中的 format 参数值需要传以下类型之一:
1. 函数中`format`参数值需要传以下值之一 (忽略大小写):
- yyyy-mm-dd hh:mm:ss
- yyyy-mm-dd hh:mm
@@ -70,14 +80,18 @@ import (
- dd-mm-yy hh:mm:ss
- yyyy/mm/dd hh:mm:ss
- yyyy/mm/dd hh:mm
- yyyy-mm-dd hh
- yyyy/mm/dd hh
- yyyy/mm/dd
- yyyy/mm
- mm/dd
- dd/mm/yy hh:mm:ss
- yyyymmdd
- mmddyy
- yyyy
- yy
- mm
- hh:mm:ss
- hh:mm
- mm:ss
### <span id="AddDay">AddDay</span>
@@ -170,6 +184,45 @@ func main() {
}
```
### <span id="AddYear">AddYear</span>
<p>将日期加/减年数。</p>
<b>函数签名:</b>
```go
func AddYear(t time.Time, year int64) time.Time
```
<b>示例:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/datetime"
)
func main() {
now := time.Now()
after1Year := datetime.AddYear(now, 1)
diff1 := after1Year.Sub(now)
before1Year := datetime.AddYear(now, -1)
diff2 := before1Year.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 8760h0m0s
// -8760h0m0s
}
```
### <span id="BeginOfMinute">BeginOfMinute</span>
<p>返回指定时间的分钟开始时间</p>
@@ -921,3 +974,309 @@ func main() {
fmt.Println(ts) //"2006-01-02T23:04:05+08:00"
}
```
### <span id="IsLeapYear">IsLeapYear</span>
<p>验证是否是闰年。</p>
<b>函数签名:</b>
```go
func IsLeapYear(year int) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
result1 := datetime.IsLeapYear(2000)
result2 := datetime.IsLeapYear(2001)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="BetweenSeconds">BetweenSeconds</span>
<p>返回两个时间的间隔秒数。</p>
<b>函数签名:</b>
```go
func BetweenSeconds(t1 time.Time, t2 time.Time) int64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := datetime.BetweenSeconds(today, tomorrow)
result2 := datetime.BetweenSeconds(today, yesterday)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 86400
// -86400
}
```
### <span id="DayOfYear">DayOfYear</span>
<p>返回参数日期是一年中的第几天。</p>
<b>函数签名:</b>
```go
func DayOfYear(t time.Time) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := datetime.DayOfYear(date1)
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
result2 := datetime.DayOfYear(date2)
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
result3 := datetime.DayOfYear(date3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 31
// 1
// 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
}
```

View File

@@ -37,12 +37,18 @@ import (
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
- [ZipAppendEntry](#ZipAppendEntry)
- [CurrentPath](#CurrentPath)
- [IsZipFile](#IsZipFile)
- [FileSize](#FileSize)
- [MTime](#MTime)
- [Sha](#Sha)
- [ReadCsvFile](#ReadCsvFile)
- [WriteCsvFile](#WriteCsvFile)
- [WriteMapsToCsv](#WriteMapsToCsv)
- [WriteStringToFile](#WriteStringToFile)
- [WriteBytesToFile](#WriteBytesToFile)
- [ReadFile](#ReadFile)
<div STYLE="page-break-after: always;"></div>
@@ -475,6 +481,34 @@ func main() {
}
```
### <span id="ZipAppendEntry">ZipAppendEntry</span>
<p>Append a single file or directory by fpath to an existing zip file.</p>
<b>Signature:</b>
```go
func ZipAppendEntry(fpath string, destPath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CurrentPath">CurrentPath</span>
<p>return current absolute path.</p>
@@ -501,7 +535,6 @@ func main() {
}
```
### <span id="IsZipFile">IsZipFile</span>
<p>Checks if file is zip file or not.</p>
@@ -661,3 +694,231 @@ func main() {
// <nil>
}
```
### <span id="WriteCsvFile">WriteCsvFile</span>
<p>Write content to target csv file.</p>
<b>Signature:</b>
```go
func WriteCsvFile(filepath string, records [][]string, append bool) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
data := [][]string{
{"Lili", "22", "female"},
{"Jim", "21", "male"},
}
err := WriteCsvFile("./testdata/test2.csv", data, false)
fmt.Println(err)
content, _ := ReadCsvFile("./testdata/test2.csv")
fmt.Println(content)
// Output:
// <nil>
// [[Lili 22 female] [Jim 21 male]]
}
```
### <span id="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>
<p>Writes bytes to target file.</p>
<b>Signature:</b>
```go
func WriteBytesToFile(filepath string, content []byte) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./bytes.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```
### <span id="WriteStringToFile">WriteStringToFile</span>
<p>Writes string to target file.</p>
<b>Signature:</b>
```go
func WriteStringToFile(filepath string, content string, append bool) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./test.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteStringToFile(filepath, "hello", true)
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```
### <span id="ReadFile">ReadFile</span>
<p>Read File/URL</p>
<b>Signature:</b>
```go
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
```
<b>Example:<span style="float:right;display:inline-block;"> </span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
reader, fn, err := ReadFile("https://httpbin.org/robots.txt")
if err != nil {
return
}
defer fn()
dat, err := io.ReadAll(reader)
if err != nil {
return
}
fmt.Println(string(dat))
// Output:
// User-agent: *
// Disallow: /deny
}
```

View File

@@ -30,19 +30,25 @@ import (
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
- [IsLink](#IsLink)
- [IsDir](#IsDir)
- [IsDir](#IsDir)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
- [ZipAppendEntry](#ZipAppendEntry)
- [CurrentPath](#CurrentPath)
- [IsZipFile](#IsZipFile)
- [FileSize](#FileSize)
- [MTime](#MTime)
- [Sha](#Sha)
- [ReadCsvFile](#ReadCsvFile)
- [WriteCsvFile](#WriteCsvFile)
- [WriteMapsToCsv](#WriteMapsToCsv)
- [WriteStringToFile](#WriteStringToFile)
- [WriteBytesToFile](#WriteBytesToFile)
- [ReadFile](#ReadFile)
<div STYLE="page-break-after: always;"></div>
@@ -451,7 +457,7 @@ func main() {
<p>zip解压缩文件并保存在目录中</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func UnZip(zipFile string, destPath string) error
@@ -475,6 +481,34 @@ func main() {
}
```
### <span id="ZipAppendEntry">ZipAppendEntry</span>
<p>通过将单个文件或目录追加到现有的zip文件</p>
<b>函数签名:</b>
```go
func ZipAppendEntry(fpath string, destPath string) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CurrentPath">CurrentPath</span>
<p>返回当前位置的绝对路径。</p>
@@ -501,7 +535,6 @@ func main() {
}
```
### <span id="IsZipFile">IsZipFile</span>
<p>判断文件是否是zip压缩文件。</p>
@@ -661,3 +694,229 @@ func main() {
// <nil>
}
```
### <span id="WriteCsvFile">WriteCsvFile</span>
<p>向csv文件写入内容。</p>
<b>函数签名:</b>
```go
func WriteCsvFile(filepath string, records [][]string, append bool) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
data := [][]string{
{"Lili", "22", "female"},
{"Jim", "21", "male"},
}
err := WriteCsvFile("./testdata/test2.csv", data, false)
fmt.Println(err)
content, _ := ReadCsvFile("./testdata/test2.csv")
fmt.Println(content)
// Output:
// <nil>
// [[Lili 22 female] [Jim 21 male]]
}
```
### <span id="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>
<p>将bytes写入文件。</p>
<b>函数签名:</b>
```go
func WriteBytesToFile(filepath string, content []byte) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./bytes.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```
### <span id="WriteStringToFile">WriteStringToFile</span>
<p>将字符串写入文件。</p>
<b>函数签名:</b>
```go
func WriteStringToFile(filepath string, content string, append bool) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./test.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteStringToFile(filepath, "hello", true)
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```
### <span id="ReadFile">ReadFile</span>
<p>读取文件或者URL</p>
<b>函数签名:</b>
```go
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
```
<b>示例:<span style="float:right;display:inline-block;"></span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
reader, fn, err := ReadFile("https://httpbin.org/robots.txt")
if err != nil {
return
}
defer fn()
dat, err := io.ReadAll(reader)
if err != nil {
return
}
fmt.Println(string(dat))
// Output:
// User-agent: *
// Disallow: /deny
}
```

View File

@@ -323,16 +323,16 @@ import (
func main() {
addOne := func(x interface{}) interface{} {
return x.(int) + 1
}
double := func(x interface{}) interface{} {
return 2 * x.(int)
}
square := func(x interface{}) interface{} {
return x.(int) * x.(int)
}
return x.(int) + 1
}
double := func(x interface{}) interface{} {
return 2 * x.(int)
}
square := func(x interface{}) interface{} {
return x.(int) * x.(int)
}
f := function.Pipeline(addOne, double, square)
f := function.Pipeline(addOne, double, square)
result := fn(2)

View File

@@ -322,16 +322,16 @@ import (
func main() {
addOne := func(x interface{}) interface{} {
return x.(int) + 1
}
double := func(x interface{}) interface{} {
return 2 * x.(int)
}
square := func(x interface{}) interface{} {
return x.(int) * x.(int)
}
return x.(int) + 1
}
double := func(x interface{}) interface{} {
return 2 * x.(int)
}
square := func(x interface{}) interface{} {
return x.(int) * x.(int)
}
f := function.Pipeline(addOne, double, square)
f := function.Pipeline(addOne, double, square)
result := fn(2)

View File

@@ -29,10 +29,19 @@ import (
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
- [CeilToFloat](#CeilToFloat)
- [CeilToString](#CeilToString)
- [FloorToFloat](#FloorToFloat)
- [FloorToString](#FloorToString)
- [AngleToRadian](#AngleToRadian)
- [RadianToAngle](#RadianToAngle)
- [PointDistance](#PointDistance)
- [IsPrime](#IsPrime)
- [GCD](#GCD)
- [LCM](#LCM)
- [Cos](#Cos)
- [Sin](#Sin)
- [Log](#Log)
<div STYLE="page-break-after: always;"></div>
@@ -235,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>
<p>Converts angle value to radian value.</p>
@@ -359,19 +512,217 @@ import (
func main() {
result1 := mathutil.IsPrime(-1)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
// Output:
// false
// false
// false
// true
}
```
### <span id="GCD">GCD</span>
<p>Return greatest common divisor (GCD) of integers.</p>
<b>Signature:</b>
```go
func GCD(integers ...int) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.GCD(1, 1)
result2 := mathutil.GCD(1, -1)
result3 := mathutil.GCD(-1, 1)
result4 := mathutil.GCD(-1, -1)
result5 := mathutil.GCD(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// 1
// -1
// -1
// 3
}
```
### <span id="LCM">LCM</span>
<p>Return Least Common Multiple (LCM) of integers.</p>
<b>Signature:</b>
```go
func LCM(integers ...int) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.LCM(1, 1)
result2 := mathutil.LCM(1, 2)
result3 := mathutil.LCM(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 18
}
```
### <span id="Cos">Cos</span>
<p>Returns the cosine of the radian argument.</p>
<b>Signature:</b>
```go
func Cos(radian float64, precision ...int) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Cos(0)
result2 := mathutil.Cos(90)
result3 := mathutil.Cos(180)
result4 := mathutil.Cos(math.Pi)
result5 := mathutil.Cos(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// -0.447
// -0.598
// -1
// 0
}
```
### <span id="Sin">Sin</span>
<p>Returns the sine of the radian argument.</p>
<b>Signature:</b>
```go
func Sin(radian float64, precision ...int) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Sin(0)
result2 := mathutil.Sin(90)
result3 := mathutil.Sin(180)
result4 := mathutil.Sin(math.Pi)
result5 := mathutil.Sin(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 0
// 0.894
// -0.801
// 0
// 1
}
```
### <span id="Log">Log</span>
<p>Returns the logarithm of base n.</p>
<b>Signature:</b>
```go
func Log(n, base float64) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Log(8, 2)
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 3
// 2.32
// 3
}
```

View File

@@ -29,10 +29,19 @@ import (
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
- [CeilToFloat](#CeilToFloat)
- [CeilToString](#CeilToString)
- [FloorToFloat](#FloorToFloat)
- [FloorToString](#FloorToString)
- [AngleToRadian](#AngleToRadian)
- [RadianToAngle](#RadianToAngle)
- [PointDistance](#PointDistance)
- [IsPrime](#IsPrime)
- [GCD](#GCD)
- [LCM](#LCM)
- [Cos](#Cos)
- [Sin](#Sin)
- [Log](#Log)
<div STYLE="page-break-after: always;"></div>
@@ -235,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>
<p>将角度值转为弧度值</p>
@@ -359,19 +513,220 @@ import (
func main() {
result1 := mathutil.IsPrime(-1)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
// Output:
// false
// false
// false
// true
}
```
### <span id="GCD">GCD</span>
<p>计算整数最大公约数。</p>
<b>函数签名:</b>
```go
func GCD(integers ...int) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.GCD(1, 1)
result2 := mathutil.GCD(1, -1)
result3 := mathutil.GCD(-1, 1)
result4 := mathutil.GCD(-1, -1)
result5 := mathutil.GCD(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// 1
// -1
// -1
// 3
}
```
### <span id="LCM">LCM</span>
<p>计算整数最小公倍数。</p>
<b>函数签名:</b>
```go
func LCM(integers ...int) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.LCM(1, 1)
result2 := mathutil.LCM(1, 2)
result3 := mathutil.LCM(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 18
}
```
### <span id="Cos">Cos</span>
<p>计算弧度的余弦值。</p>
<b>函数签名:</b>
```go
func Cos(radian float64, precision ...int) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Cos(0)
result2 := mathutil.Cos(90)
result3 := mathutil.Cos(180)
result4 := mathutil.Cos(math.Pi)
result5 := mathutil.Cos(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// -0.447
// -0.598
// -1
// 0
}
```
### <span id="Sin">Sin</span>
<p>计算弧度的正弦值。</p>
<b>函数签名:</b>
```go
func Sin(radian float64, precision ...int) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Sin(0)
result2 := mathutil.Sin(90)
result3 := mathutil.Sin(180)
result4 := mathutil.Sin(math.Pi)
result5 := mathutil.Sin(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 0
// 0.894
// -0.801
// 0
// 1
}
```
### <span id="Log">Log</span>
<p>计算以base为底n的对数。</p>
<b>函数签名:</b>
```go
func Log(n, base float64) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Log(8, 2)
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 3
// 2.32
// 3
}
```

View File

@@ -586,9 +586,9 @@ func main() {
}
```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpGet">HttpGet</span>
<p>Send http get request.</p>
<p>Send http get request. (Deprecated: use SendRequest for replacement)</p>
<b>Signature:</b>
@@ -628,9 +628,9 @@ func main() {
}
```
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpPost">HttpPost</span>
<p>Send http post request.</p>
<p>Send http post request. (Deprecated: use SendRequest for replacement)</p>
<b>Signature:</b>
@@ -658,28 +658,30 @@ import (
func main() {
url := "https://jsonplaceholder.typicode.com/todos"
header := map[string]string{
"Content-Type": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
// "Content-Type": "multipart/form-data",
}
type Todo struct {
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, "TestAddToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPost(url, header, nil, bodyParams)
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "TestToDo")
// postData := make(map[string]string)
// postData["userId"] = "1"
// postData["title"] = "title"
resp, err := netutil.HttpPost(apiUrl, header, nil, postData)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
```
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpPut">HttpPut</span>
<p>Send http put request.</p>
<p>Send http put request. (Deprecated: use SendRequest for replacement)</p>
<b>Signature:</b>
@@ -727,9 +729,9 @@ func main() {
}
```
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpDelete">HttpDelete</span>
<p>Send http delete request.</p>
<p>Send http delete request. (Deprecated: use SendRequest for replacement)</p>
<b>Signature:</b>
@@ -766,9 +768,9 @@ func main() {
}
```
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpPatch">HttpPatch</span>
<p>Send http patch request.</p>
<p>Send http patch request. (Deprecated: use SendRequest for replacement)</p>
<b>Signature:</b>

View File

@@ -585,9 +585,9 @@ func main() {
}
```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpGet">HttpGet</span>
<p>发送http get请求</p>
<p>发送http get请求。(已废弃: 使用SendRequest)</p>
<b>函数签名:</b>
@@ -627,9 +627,9 @@ func main() {
}
```
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpPost">HttpPost</span>
<p>发送http post请求</p>
<p>发送http post请求。(已废弃: 使用SendRequest)</p>
<b>函数签名:</b>
@@ -657,28 +657,30 @@ import (
func main() {
url := "https://jsonplaceholder.typicode.com/todos"
header := map[string]string{
"Content-Type": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
// "Content-Type": "multipart/form-data",
}
type Todo struct {
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, "TestAddToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPost(url, header, nil, bodyParams)
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "TestToDo")
// postData := make(map[string]string)
// postData["userId"] = "1"
// postData["title"] = "title"
resp, err := netutil.HttpPost(apiUrl, header, nil, postData)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpPut">HttpPut</span>
<p>发送http put请求</p>
<p>发送http put请求。(已废弃: 使用SendRequest)</p>
<b>函数签名:</b>
@@ -726,9 +728,9 @@ func main() {
}
```
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpDelete">HttpDelete</span>
<p>发送http delete请求</p>
<p>发送http delete请求。(已废弃: 使用SendRequest)</p>
<b>函数签名:</b>
@@ -765,9 +767,9 @@ func main() {
}
```
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
### <span id="HttpPatch">HttpPatch</span>
<p>发送http patch请求</p>
<p>发送http patch请求。(已废弃: 使用SendRequest)</p>
<b>函数签名:</b>

View File

@@ -30,6 +30,7 @@ import (
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)
- [UUIdV4](#UUIdV4)
- [RandUniqueIntSlice](#RandUniqueIntSlice)
<div STYLE="page-break-after: always;"></div>
@@ -245,3 +246,29 @@ func main() {
fmt.Println(uuid)
}
```
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
<p>Generate a slice of random int of length n that do not repeat.</p>
<b>Signature:</b>
```go
func RandUniqueIntSlice(n, min, max int) []int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
result := RandUniqueIntSlice(5, 0, 10)
fmt.Println(result) //[0 4 7 1 5] (random)
}
```

View File

@@ -30,6 +30,7 @@ import (
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)
- [UUIdV4](#UUIdV4)
- [RandUniqueIntSlice](#RandUniqueIntSlice)
<div STYLE="page-break-after: always;"></div>
@@ -245,3 +246,29 @@ func main() {
fmt.Println(uuid)
}
```
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
<p>生成一个不重复的长度为n的随机int切片。</p>
<b>函数签名:</b>
```go
func RandUniqueIntSlice(n, min, max int) []int
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
result := RandUniqueIntSlice(5, 0, 10)
fmt.Println(result) //[0 4 7 1 5] (random)
}
```

View File

@@ -62,6 +62,7 @@ import (
- [Union](#Union)
- [UpdateByIndex](#UpdateByIndex)
- [Without](#Without)
- [Join](#Join)
<div STYLE="page-break-after: always;"></div>
@@ -1172,3 +1173,36 @@ func main() {
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
}
```

View File

@@ -62,6 +62,8 @@ import (
- [Union](#Union)
- [UpdateByIndex](#UpdateByIndex)
- [Without](#Without)
- [Join](#Join)
<div STYLE="page-break-after: always;"></div>
@@ -1168,3 +1170,36 @@ func main() {
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
}
```

View File

@@ -28,6 +28,8 @@ import (
- [BeforeLast](#BeforeLast)
- [CamelCase](#CamelCase)
- [Capitalize](#Capitalize)
- [ContainsAll](#ContainsAll)
- [ContainsAny](#ContainsAny)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
- [UpperKebabCase](#UpperKebabCase)
@@ -51,6 +53,13 @@ import (
- [HasPrefixAny](#HasPrefixAny)
- [HasSuffixAny](#HasSuffixAny)
- [IndexOffset](#IndexOffset)
- [ReplaceWithMap](#ReplaceWithMap)
- [Trim](#Trim)
- [SplitAndTrim](#SplitAndTrim)
- [HideString](#HideString)
- [RemoveWhiteSpace](#RemoveWhiteSpace)
- [SubInBetween](#SubInBetween)
- [HammingDistance](#HammingDistance)
<div STYLE="page-break-after: always;"></div>
@@ -851,13 +860,13 @@ import (
func main() {
result1 := strutil.StringToBytes("abc")
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [97 98 99]
// true
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [97 98 99]
// true
}
```
@@ -881,11 +890,11 @@ import (
func main() {
bytes := []byte{'a', 'b', 'c'}
result := strutil.BytesToString(bytes)
result := strutil.BytesToString(bytes)
fmt.Println(result)
// Output:
// abc
fmt.Println(result)
// Output:
// abc
}
```
@@ -909,16 +918,16 @@ import (
func main() {
result1 := strutil.IsBlank("")
result2 := strutil.IsBlank("\t\v\f\n")
result3 := strutil.IsBlank(" 中文")
result2 := strutil.IsBlank("\t\v\f\n")
result3 := strutil.IsBlank(" 中文")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
```
@@ -942,13 +951,13 @@ import (
func main() {
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
@@ -972,13 +981,13 @@ import (
func main() {
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
@@ -1003,22 +1012,332 @@ import (
func main() {
str := "foo bar hello world"
result1 := strutil.IndexOffset(str, "o", 5)
result2 := strutil.IndexOffset(str, "o", 0)
result3 := strutil.IndexOffset(str, "d", len(str)-1)
result4 := strutil.IndexOffset(str, "d", len(str))
result5 := strutil.IndexOffset(str, "f", -1)
result1 := strutil.IndexOffset(str, "o", 5)
result2 := strutil.IndexOffset(str, "o", 0)
result3 := strutil.IndexOffset(str, "d", len(str)-1)
result4 := strutil.IndexOffset(str, "d", len(str))
result5 := strutil.IndexOffset(str, "f", -1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 12
// 1
// 18
// -1
// -1
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 12
// 1
// 18
// -1
// -1
}
```
### <span id="ReplaceWithMap">ReplaceWithMap</span>
<p>Returns a copy of `str`, which is replaced by a map in unordered way, case-sensitively.</p>
<b>Signature:</b>
```go
func ReplaceWithMap(str string, replaces map[string]string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "ac ab ab ac"
replaces := map[string]string{
"a": "1",
"b": "2",
}
result := strutil.ReplaceWithMap(str, replaces)
fmt.Println(result)
// Output:
// 1c 12 12 1c
}
```
### <span id="Trim">Trim</span>
<p>Strips whitespace (or other characters) from the beginning and end of a string. The optional parameter `characterMask` specifies the additional stripped characters.</p>
<b>Signature:</b>
```go
func Trim(str string, characterMask ...string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
result1 := strutil.Trim("\nabcd")
str := "$ ab cd $ "
result2 := strutil.Trim(str)
result3 := strutil.Trim(str, "$")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// abcd
// $ ab cd $
// ab cd
}
```
### <span id="SplitAndTrim">SplitAndTrim</span>
<p>Splits string `str` by a string `delimiter` to a slice, and calls Trim to every element of slice. It ignores the elements which are empty after Trim.</p>
<b>Signature:</b>
```go
func SplitAndTrim(str, delimiter string, characterMask ...string) []string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := " a,b, c,d,$1 "
result1 := strutil.SplitAndTrim(str, ",")
result2 := strutil.SplitAndTrim(str, ",", "$")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [a b c d $1]
// [a b c d 1]
}
```
### <span id="HideString">HideString</span>
<p>HideString hide some chars in source string with param `replaceChar`. replace range is origin[start : end]. [start, end).</p>
<b>Signature:</b>
```go
func HideString(origin string, start, end int, replaceChar string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "13242658976"
result1 := strutil.HideString(str, 3, 3, "*")
result2 := strutil.HideString(str, 3, 4, "*")
result3 := strutil.HideString(str, 3, 7, "*")
result4 := strutil.HideString(str, 7, 11, "*")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 13242658976
// 132*2658976
// 132****8976
// 1324265****
}
```
### <span id="ContainsAll">ContainsAll</span>
<p>Return true if target string contains all the substrings.</p>
<b>Signature:</b>
```go
func ContainsAll(str string, substrs []string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "hello world"
result1 := strutil.ContainsAll(str, []string{"hello", "world"})
result2 := strutil.ContainsAll(str, []string{"hello", "abc"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="ContainsAny">ContainsAny</span>
<p>Return true if target string contains any one of the substrings.</p>
<b>Signature:</b>
```go
func ContainsAny(str string, substrs []string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "hello world"
result1 := strutil.ContainsAny(str, []string{"hello", "world"})
result2 := strutil.ContainsAny(str, []string{"hello", "abc"})
result3 := strutil.ContainsAny(str, []string{"123", "abc"})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
```
### <span id="RemoveWhiteSpace">RemoveWhiteSpace</span>
<p>Remove whitespace characters from a string. when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.</p>
<b>Signature:</b>
```go
func RemoveWhiteSpace(str string, repalceAll bool) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := " hello \r\n \t world"
result1 := strutil.RemoveWhiteSpace(str, true)
result2 := strutil.RemoveWhiteSpace(str, false)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// helloworld
// 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
}
```

View File

@@ -27,6 +27,8 @@ import (
- [Before](#Before)
- [BeforeLast](#BeforeLast)
- [CamelCase](#CamelCase)
- [ContainsAll](#ContainsAll)
- [ContainsAny](#ContainsAny)
- [Capitalize](#Capitalize)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
@@ -51,6 +53,14 @@ import (
- [HasPrefixAny](#HasPrefixAny)
- [HasSuffixAny](#HasSuffixAny)
- [IndexOffset](#IndexOffset)
- [ReplaceWithMap](#ReplaceWithMap)
- [Trim](#Trim)
- [SplitAndTrim](#SplitAndTrim)
- [HideString](#HideString)
- [RemoveWhiteSpace](#RemoveWhiteSpace)
- [SubInBetween](#SubInBetween)
- [HammingDistance](#HammingDistance)
<div STYLE="page-break-after: always;"></div>
@@ -832,7 +842,6 @@ func main() {
}
```
### <span id="RemoveNonPrintable">RemoveNonPrintable</span>
<p>删除字符串中不可打印的字符。</p>
@@ -883,13 +892,13 @@ import (
func main() {
result1 := strutil.StringToBytes("abc")
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [97 98 99]
// true
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [97 98 99]
// true
}
```
@@ -913,11 +922,11 @@ import (
func main() {
bytes := []byte{'a', 'b', 'c'}
result := strutil.BytesToString(bytes)
result := strutil.BytesToString(bytes)
fmt.Println(result)
// Output:
// abc
fmt.Println(result)
// Output:
// abc
}
```
@@ -941,16 +950,16 @@ import (
func main() {
result1 := strutil.IsBlank("")
result2 := strutil.IsBlank("\t\v\f\n")
result3 := strutil.IsBlank(" 中文")
result2 := strutil.IsBlank("\t\v\f\n")
result3 := strutil.IsBlank(" 中文")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
```
@@ -974,13 +983,13 @@ import (
func main() {
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
@@ -1004,13 +1013,13 @@ import (
func main() {
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
@@ -1035,22 +1044,333 @@ import (
func main() {
str := "foo bar hello world"
result1 := strutil.IndexOffset(str, "o", 5)
result2 := strutil.IndexOffset(str, "o", 0)
result3 := strutil.IndexOffset(str, "d", len(str)-1)
result4 := strutil.IndexOffset(str, "d", len(str))
result5 := strutil.IndexOffset(str, "f", -1)
result1 := strutil.IndexOffset(str, "o", 5)
result2 := strutil.IndexOffset(str, "o", 0)
result3 := strutil.IndexOffset(str, "d", len(str)-1)
result4 := strutil.IndexOffset(str, "d", len(str))
result5 := strutil.IndexOffset(str, "f", -1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 12
// 1
// 18
// -1
// -1
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 12
// 1
// 18
// -1
// -1
}
```
### <span id="ReplaceWithMap">ReplaceWithMap</span>
<p>返回`str`的副本以无序的方式被map替换区分大小写。</p>
<b>函数签名:</b>
```go
func ReplaceWithMap(str string, replaces map[string]string) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "ac ab ab ac"
replaces := map[string]string{
"a": "1",
"b": "2",
}
result := strutil.ReplaceWithMap(str, replaces)
fmt.Println(result)
// Output:
// 1c 12 12 1c
}
```
### <span id="Trim">Trim</span>
<p>从字符串的开头和结尾去除空格(或其他字符)。 可选参数 characterMask 指定额外的剥离字符。</p>
<b>函数签名:</b>
```go
func Trim(str string, characterMask ...string) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
result1 := strutil.Trim("\nabcd")
str := "$ ab cd $ "
result2 := strutil.Trim(str)
result3 := strutil.Trim(str, "$")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// abcd
// $ ab cd $
// ab cd
}
```
### <span id="SplitAndTrim">SplitAndTrim</span>
<p>将字符串str按字符串delimiter拆分为一个切片并对该数组的每个元素调用Trim。忽略Trim后为空的元素。</p>
<b>函数签名:</b>
```go
func SplitAndTrim(str, delimiter string, characterMask ...string) []string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := " a,b, c,d,$1 "
result1 := strutil.SplitAndTrim(str, ",")
result2 := strutil.SplitAndTrim(str, ",", "$")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [a b c d $1]
// [a b c d 1]
}
```
### <span id="HideString">HideString</span>
<p>使用参数`replaceChar`隐藏源字符串中的一些字符。替换范围是 origin[start : end]。</p>
<b>函数签名:</b>
```go
func HideString(origin string, start, end int, replaceChar string) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "13242658976"
result1 := strutil.HideString(str, 3, 3, "*")
result2 := strutil.HideString(str, 3, 4, "*")
result3 := strutil.HideString(str, 3, 7, "*")
result4 := strutil.HideString(str, 7, 11, "*")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 13242658976
// 132*2658976
// 132****8976
// 1324265****
}
```
### <span id="ContainsAll">ContainsAll</span>
<p>判断字符串是否包括全部给定的子字符串切片。</p>
<b>函数签名:</b>
```go
func ContainsAll(str string, substrs []string) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "hello world"
result1 := strutil.ContainsAll(str, []string{"hello", "world"})
result2 := strutil.ContainsAll(str, []string{"hello", "abc"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="ContainsAny">ContainsAny</span>
<p>判断字符串是否包括给定的子字符串切片中任意一个子字符串。</p>
<b>函数签名:</b>
```go
func ContainsAny(str string, substrs []string) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "hello world"
result1 := strutil.ContainsAny(str, []string{"hello", "world"})
result2 := strutil.ContainsAny(str, []string{"hello", "abc"})
result3 := strutil.ContainsAny(str, []string{"123", "abc"})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
```
### <span id="RemoveWhiteSpace">RemoveWhiteSpace</span>
<p>删除字符串中的空格当设置repalceAll为true时删除全部空格为false时替换多个空格为1个空格。</p>
<b>函数签名:</b>
```go
func RemoveWhiteSpace(str string, repalceAll bool) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := " hello \r\n \t world"
result1 := strutil.RemoveWhiteSpace(str, true)
result2 := strutil.RemoveWhiteSpace(str, false)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// helloworld
// 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
}
```

View File

@@ -54,7 +54,16 @@ import (
- [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
- [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>
@@ -1026,4 +1035,301 @@ func main() {
// true
// 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
}
```

View File

@@ -55,6 +55,15 @@ import (
- [IsGBK](#IsGBK)
- [IsASCII](#IsASCII)
- [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>
@@ -958,6 +967,7 @@ func main() {
fmt.Println("data encoding is unknown")
}
```
### <span id="IsASCII">IsASCII</span>
<p>验证字符串全部为ASCII字符。</p>
@@ -1036,4 +1046,301 @@ func main() {
// true
// 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
}
```

View File

@@ -17,12 +17,16 @@ import (
"io"
"io/fs"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"sync"
"github.com/duke-git/lancet/validator"
)
// 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/
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
@@ -168,7 +172,15 @@ func ListFileNames(path string) ([]string, error) {
}
// 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)
if err != nil {
return err
@@ -178,7 +190,33 @@ func Zip(fpath string, destPath string) error {
archive := zip.NewWriter(zipFile)
defer archive.Close()
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
return addFileToArchive1(filePath, archive)
}
func zipFolder(folderPath string, destPath string) error {
outFile, err := os.Create(destPath)
if err != nil {
return err
}
defer outFile.Close()
w := zip.NewWriter(outFile)
err = addFileToArchive2(w, folderPath, "")
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return nil
}
func addFileToArchive1(fpath string, archive *zip.Writer) error {
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
@@ -194,26 +232,53 @@ func Zip(fpath string, destPath string) error {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if !info.IsDir() {
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
if err != nil {
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
}
@@ -260,6 +325,64 @@ func UnZip(zipFile string, destPath string) error {
return nil
}
// ZipAppendEntry append a single file or directory by fpath to an existing zip file.
// Play: https://go.dev/play/p/cxvaT8TRNQp
func ZipAppendEntry(fpath string, destPath string) error {
tempFile, err := os.CreateTemp("", "temp.zip")
if err != nil {
return err
}
defer os.Remove(tempFile.Name())
zipReader, err := zip.OpenReader(destPath)
if err != nil {
return err
}
archive := zip.NewWriter(tempFile)
for _, zipItem := range zipReader.File {
zipItemReader, err := zipItem.Open()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(zipItem.FileInfo())
if err != nil {
return err
}
header.Name = zipItem.Name
targetItem, err := archive.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(targetItem, zipItemReader)
if err != nil {
return err
}
}
err = addFileToArchive1(fpath, archive)
if err != nil {
return err
}
err = zipReader.Close()
if err != nil {
return err
}
err = archive.Close()
if err != nil {
return err
}
err = tempFile.Close()
if err != nil {
return err
}
return CopyFile(tempFile.Name(), destPath)
}
func safeFilepathJoin(path1, path2 string) (string, error) {
relPath, err := filepath.Rel(".", path2)
if err != nil || strings.HasPrefix(relPath, "..") {
@@ -330,7 +453,7 @@ func CurrentPath() string {
var absPath string
_, filename, _, ok := runtime.Caller(1)
if ok {
absPath = path.Dir(filename)
absPath = filepath.Dir(filename)
}
return absPath
@@ -370,7 +493,7 @@ func MTime(filepath string) (int64, error) {
return f.ModTime().Unix(), nil
}
// MTime returns file sha value, param `shaType` should be 1, 256 or 512.
// Sha returns file sha value, param `shaType` should be 1, 256 or 512.
func Sha(filepath string, shaType ...int) (string, error) {
file, err := os.Open(filepath)
if err != nil {
@@ -404,18 +527,258 @@ func Sha(filepath string, shaType ...int) (string, error) {
}
// 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)
if err != nil {
return nil, err
}
defer f.Close()
csvReader := csv.NewReader(f)
records, err := csvReader.ReadAll()
reader := csv.NewReader(f)
if len(delimiter) > 0 {
reader.Comma = delimiter[0]
}
records, err := reader.ReadAll()
if err != nil {
return nil, err
}
return records, nil
}
// WriteCsvFile write content to target csv file.
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error {
flag := os.O_RDWR | os.O_CREATE
if append {
flag = flag | os.O_APPEND
}
f, err := os.OpenFile(filepath, flag, 0644)
if err != nil {
return err
}
defer f.Close()
writer := csv.NewWriter(f)
// 设置默认分隔符为逗号,除非另外指定
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)
}
// 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.
func WriteStringToFile(filepath string, content string, append bool) error {
flag := os.O_RDWR | os.O_CREATE
if append {
flag = flag | os.O_APPEND
}
f, err := os.OpenFile(filepath, flag, 0644)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(content)
return err
}
// WriteBytesToFile write bytes to target file.
func WriteBytesToFile(filepath string, content []byte) error {
f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(content)
return err
}
// ReadFile get file reader by a url or a local file.
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) {
switch {
case validator.IsUrl(path):
resp, err := http.Get(path)
if err != nil {
return nil, func() {}, err
}
return resp.Body, func() { resp.Body.Close() }, nil
case IsExist(path):
reader, err := os.Open(path)
if err != nil {
return nil, func() {}, err
}
return reader, func() { reader.Close() }, nil
default:
return nil, func() {}, errors.New("unknown file type")
}
}
// 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)
}

View File

@@ -1,6 +1,7 @@
package fileutil
import (
"io"
"os"
"testing"
@@ -182,6 +183,44 @@ func TestZipAndUnZip(t *testing.T) {
os.RemoveAll(unZipPath)
}
func TestZipAppendEntry(t *testing.T) {
assert := internal.NewAssert(t, "TestZipAppendEntry")
zipFile := "./text.zip"
err := CopyFile("./testdata/file.go.zip", zipFile)
assert.IsNil(err)
srcFile := "./text.txt"
CreateFile(srcFile)
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, os.ModePerm)
_, err = file.WriteString("hello\nworld")
if err != nil {
t.Fail()
}
file.Close()
err = ZipAppendEntry(srcFile, zipFile)
assert.IsNil(err)
err = ZipAppendEntry("./testdata", zipFile)
assert.IsNil(err)
unZipPath := "./unzip"
err = UnZip(zipFile, unZipPath)
assert.IsNil(err)
assert.Equal(true, IsExist("./unzip/text.txt"))
assert.Equal(true, IsExist("./unzip/file.go"))
assert.Equal(true, IsExist("./unzip/testdata/file.go.zip"))
assert.Equal(true, IsExist("./unzip/testdata/test.txt"))
os.Remove(srcFile)
os.Remove(zipFile)
os.RemoveAll(unZipPath)
}
func TestFileMode(t *testing.T) {
assert := internal.NewAssert(t, "TestFileMode")
@@ -244,19 +283,23 @@ func TestFileSize(t *testing.T) {
}
func TestMTime(t *testing.T) {
assert := internal.NewAssert(t, "TestMTime")
// assert := internal.NewAssert(t, "TestMTime")
mtime, err := MTime("./testdata/test.txt")
// mtime, err := MTime("./testdata/test.txt")
assert.IsNil(err)
assert.Equal(int64(1682478195), mtime)
// assert.IsNil(err)
// assert.Equal(int64(1682478195), mtime)
}
func TestSha(t *testing.T) {
assert := internal.NewAssert(t, "TestSha")
sha1, err := Sha("./testdata/test.txt", 1)
assert.IsNil(err)
sha256, err := Sha("./testdata/test.txt", 256)
assert.IsNil(err)
sha512, err := Sha("./testdata/test.txt", 512)
assert.IsNil(err)
@@ -268,7 +311,7 @@ func TestSha(t *testing.T) {
func TestReadCsvFile(t *testing.T) {
assert := internal.NewAssert(t, "TestReadCsvFile")
content, err := ReadCsvFile("./testdata/test.csv")
content, err := ReadCsvFile("./testdata/demo.csv")
t.Log(content)
assert.IsNil(err)
@@ -277,3 +320,132 @@ func TestReadCsvFile(t *testing.T) {
assert.Equal(3, len(content[0]))
assert.Equal("Bob", content[0][0])
}
func TestWriteCsvFile(t *testing.T) {
assert := internal.NewAssert(t, "TestWriteCsvFile")
csvFilePath := "./testdata/test1.csv"
content := [][]string{
{"Lili", "22", "female"},
{"Jim", "21", "male"},
}
err := WriteCsvFile(csvFilePath, content, false)
assert.IsNil(err)
readContent, err := ReadCsvFile(csvFilePath)
assert.IsNil(err)
assert.Equal(2, len(readContent))
assert.Equal(3, len(readContent[0]))
assert.Equal("Lili", content[0][0])
}
func 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) {
assert := internal.NewAssert(t, "TestWriteStringToFile")
filepath := "./test.txt"
file, err := os.Create(filepath)
if err != nil {
t.Fail()
}
defer file.Close()
err = WriteStringToFile(filepath, "hello", false)
if err != nil {
t.Fail()
}
content1, err := ReadFileToString(filepath)
if err != nil {
t.Fail()
}
err = WriteStringToFile(filepath, " world", true)
if err != nil {
t.Fail()
}
content2, err := os.ReadFile(filepath)
if err != nil {
t.Fail()
}
assert.Equal("hello", content1)
assert.Equal("hello world", string(content2))
os.Remove(filepath)
}
func TestWriteBytesToFile(t *testing.T) {
assert := internal.NewAssert(t, "TestWriteBytesToFile")
filepath := "./bytes.txt"
file, err := os.Create(filepath)
if err != nil {
t.Fail()
}
defer file.Close()
err = WriteBytesToFile(filepath, []byte("hello"))
if err != nil {
t.Fail()
}
content, err := os.ReadFile(filepath)
if err != nil {
t.Fail()
}
assert.Equal("hello", string(content))
os.Remove(filepath)
}
func TestReadFile(t *testing.T) {
reader, close, err := ReadFile("https://httpbin.org/robots.txt")
if err != nil {
t.Fail()
}
defer close()
dat, err := io.ReadAll(reader)
if err != nil {
t.Fail()
}
want := `User-agent: *
Disallow: /deny
`
internal.NewAssert(t, "TestReadFile").Equal(want, string(dat))
}

3
fileutil/testdata/test1.csv vendored Normal file
View File

@@ -0,0 +1,3 @@
Lili,22,female
Jim,21,male
1 Lili 22 female
2 Jim 21 male

3
fileutil/testdata/test4.csv vendored Normal file
View File

@@ -0,0 +1,3 @@
Name;Age;Gender
Lili;22;female
Jim;21;male
1 Name Age Gender
2 Lili 22 female
3 Jim 21 male

View File

@@ -8,41 +8,36 @@ import (
"encoding/json"
"fmt"
"io"
"math"
"strconv"
"strings"
"unicode"
"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.
// if value is invalid number string eg "aa", return empty string
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
func Comma(value interface{}, symbol string) string {
if validator.IsInt(value) {
v, err := convertor.ToInt(value)
if err != nil {
return ""
}
return symbol + commaInt(v)
}
numString := convertor.ToString(value)
if validator.IsFloat(value) {
v, err := convertor.ToFloat(value)
if err != nil {
return ""
}
return symbol + commaFloat(v)
}
if strutil.IsString(value) {
v := fmt.Sprintf("%v", value)
if validator.IsNumberStr(v) {
return symbol + commaStr(v)
}
_, err := strconv.ParseFloat(numString, 64)
if err != nil {
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.
@@ -177,3 +172,50 @@ func ParseDecimalBytes(size string) (uint64, error) {
func ParseBinaryBytes(size string) (uint64, error) {
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)
}

View File

@@ -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)
}

View File

@@ -5,6 +5,7 @@
package internal
import (
"bytes"
"fmt"
"reflect"
"runtime"
@@ -36,6 +37,52 @@ func (a *Assert) Equal(expected, actual interface{}) {
}
}
// EqualValues asserts that two objects are equal or convertable to the same types and equal.
// https://github.com/stretchr/testify/assert/assertions.go
func (a *Assert) EqualValues(expected, actual interface{}) {
if !objectsAreEqualValues(expected, actual) {
makeTestFailed(a.T, a.CaseName, expected, actual)
}
}
func objectsAreEqualValues(expected, actual interface{}) bool {
if objectsAreEqual(expected, actual) {
return true
}
actualType := reflect.TypeOf(actual)
if actualType == nil {
return false
}
expectedValue := reflect.ValueOf(expected)
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
// Attempt comparison after type conversion
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
}
return false
}
func objectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
}
exp, ok := expected.([]byte)
if !ok {
return reflect.DeepEqual(expected, actual)
}
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
}
// NotEqual check if expected is not equal with actual
func (a *Assert) NotEqual(expected, actual interface{}) {
if compare(expected, actual) == compareEqual {

View File

@@ -91,6 +91,34 @@ func TruncRound(x float64, n int) float64 {
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.
func AngleToRadian(angle float64) float64 {
radian := angle * (math.Pi / 180)
@@ -126,3 +154,71 @@ func IsPrime(n int) bool {
return true
}
// GCD return greatest common divisor (GCD) of integers.
func GCD(integers ...int) int {
result := integers[0]
for k := range integers {
result = gcd(integers[k], result)
if result == 1 {
return 1
}
}
return result
}
// find greatest common divisor (GCD)
func gcd(a, b int) int {
if b == 0 {
return a
}
return gcd(b, a%b)
}
// LCM return Least Common Multiple (LCM) of integers.
func LCM(integers ...int) int {
result := integers[0]
for k := range integers {
result = lcm(integers[k], result)
}
return result
}
// find Least Common Multiple (LCM) via GCD.
func lcm(a, b int) int {
if a == 0 || b == 0 {
panic("lcm function: provide non zero integers only.")
}
return a * b / gcd(a, b)
}
// Cos returns the cosine of the radian argument.
func Cos(radian float64, precision ...int) float64 {
t := 1.0 / (2.0 * math.Pi)
radian *= t
radian -= 0.25 + math.Floor(radian+0.25)
radian *= 16.0 * (math.Abs(radian) - 0.5)
radian += 0.225 * radian * (math.Abs(radian) - 1.0)
if len(precision) == 1 {
return TruncRound(radian, precision[0])
}
return TruncRound(radian, 3)
}
// Cos returns the sine of the radian argument.
func Sin(radian float64, precision ...int) float64 {
return Cos((math.Pi / 2) - radian)
}
// Log returns the logarithm of base n.
func Log(n, base float64) float64 {
return math.Log(n) / math.Log(base)
}

View File

@@ -114,3 +114,112 @@ func TestIsPrime(t *testing.T) {
assert.Equal(true, IsPrime(3))
assert.Equal(false, IsPrime(4))
}
func TestGCD(t *testing.T) {
assert := internal.NewAssert(t, "TestGCD")
assert.Equal(1, GCD(1, 1))
assert.Equal(1, GCD(1, -1))
assert.Equal(-1, GCD(-1, 1))
assert.Equal(-1, GCD(-1, -1))
assert.Equal(1, GCD(1, 0))
assert.Equal(1, GCD(0, 1))
assert.Equal(-1, GCD(-1, 0))
assert.Equal(-1, GCD(0, -1))
assert.Equal(1, GCD(1, -2))
assert.Equal(1, GCD(-2, 1))
assert.Equal(-1, GCD(-1, 2))
assert.Equal(-1, GCD(2, -1))
assert.Equal(-1, GCD(-1, -2))
assert.Equal(-1, GCD(-2, -1))
assert.Equal(-9, GCD(-27, -36))
assert.Equal(3, GCD(3, 6, 9))
}
func TestLCM(t *testing.T) {
assert := internal.NewAssert(t, "TestLCM")
assert.Equal(1, LCM(1))
assert.Equal(-1, LCM(-1))
assert.Equal(-1, LCM(1, -1))
assert.Equal(1, LCM(-1, 1))
assert.Equal(1, LCM(1, 1))
assert.Equal(-1, LCM(-1, -1))
assert.Equal(2, LCM(1, 2))
assert.Equal(18, LCM(3, 6, 9))
}
func TestCos(t *testing.T) {
assert := internal.NewAssert(t, "TestCos")
assert.EqualValues(1, Cos(0))
assert.EqualValues(-0.447, Cos(90))
assert.EqualValues(-0.598, Cos(180))
assert.EqualValues(-1, Cos(math.Pi))
assert.EqualValues(0, Cos(math.Pi/2))
}
func TestSin(t *testing.T) {
assert := internal.NewAssert(t, "TestSin")
assert.EqualValues(0, Sin(0))
assert.EqualValues(0.894, Sin(90))
assert.EqualValues(-0.801, Sin(180))
assert.EqualValues(0, Sin(math.Pi))
assert.EqualValues(1, Sin(math.Pi/2))
}
func TestLog(t *testing.T) {
assert := internal.NewAssert(t, "TestLog")
assert.EqualValues(3, Log(8, 2))
assert.EqualValues(3, TruncRound(Log(27, 3), 0))
assert.EqualValues(2.32, TruncRound(Log(5, 2), 2))
}
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))
}

View File

@@ -18,9 +18,11 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"reflect"
"regexp"
"sort"
@@ -93,6 +95,7 @@ type HttpRequest struct {
Headers http.Header
QueryParams url.Values
FormData url.Values
File *File
Body []byte
}
@@ -180,7 +183,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
client.setQueryParam(req, rawUrl, request.QueryParams)
if request.FormData != nil {
client.setFormData(req, request.FormData)
if request.File != nil {
err = client.setFormData(req, request.FormData, setFile(request.File))
} else {
err = client.setFormData(req, request.FormData, nil)
}
}
client.Request = req
@@ -244,10 +251,79 @@ func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryP
return nil
}
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
formData := []byte(values.Encode())
req.Body = ioutil.NopCloser(bytes.NewReader(formData))
req.ContentLength = int64(len(formData))
func (client *HttpClient) setFormData(req *http.Request, values url.Values, setFile SetFileFunc) error {
if setFile != nil {
err := setFile(req, values)
if err != nil {
return err
}
} else {
formData := []byte(values.Encode())
req.Body = io.NopCloser(bytes.NewReader(formData))
req.ContentLength = int64(len(formData))
}
return nil
}
type SetFileFunc func(req *http.Request, values url.Values) error
// File struct is a combination of file attributes
type File struct {
Content []byte
Path string
FieldName string
FileName string
}
// setFile set parameters for http request formdata file upload
func setFile(f *File) SetFileFunc {
return func(req *http.Request, values url.Values) error {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
for key, vals := range values {
for _, val := range vals {
err := writer.WriteField(key, val)
if err != nil {
return err
}
}
}
if f.Content != nil {
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
if err != nil {
return err
}
part.Write(f.Content)
} else if f.Path != "" {
file, err := os.Open(f.Path)
if err != nil {
return err
}
defer file.Close()
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
if err != nil {
return err
}
_, err = io.Copy(part, file)
if err != nil {
return err
}
}
err := writer.Close()
if err != nil {
return err
}
req.Body = io.NopCloser(body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.ContentLength = int64(body.Len())
return nil
}
}
// validateRequest check if a request has url, and valid method.

View File

@@ -1,11 +1,15 @@
package netutil
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"github.com/duke-git/lancet/internal"
@@ -51,23 +55,23 @@ func TestHttpPost(t *testing.T) {
func TestHttpPostFormData(t *testing.T) {
apiUrl := "https://jsonplaceholder.typicode.com/todos"
header := map[string]string{
// "Content-Type": "application/x-www-form-urlencoded",
"Content-Type": "multipart/form-data",
}
type Todo struct {
UserId int `json:"userId"`
Title string `json:"title"`
"Content-Type": "application/x-www-form-urlencoded",
// "Content-Type": "multipart/form-data",
}
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "TestAddToDo")
postData.Add("title", "TestToDo")
resp, err := HttpPost(apiUrl, header, postData, nil)
// postData := make(map[string]string)
// postData["userId"] = "1"
// postData["title"] = "title"
resp, err := HttpPost(apiUrl, header, nil, postData)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
@@ -249,3 +253,108 @@ func TestStructToUrlValues(t *testing.T) {
assert.Equal("456", queryValues2.Get("userId"))
assert.Equal("", queryValues2.Get("name"))
}
func handleFileRequest(t *testing.T, w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(1024)
if err != nil {
t.Fatal(err)
}
key1 := r.FormValue("key1")
expectedKey1 := "value1"
if key1 != expectedKey1 {
t.Fatalf("expected %s, got %s", expectedKey1, key1)
}
key2 := r.FormValue("key2")
expectedKey2 := "value2"
if key2 != expectedKey2 {
t.Fatalf("expected %s, got %s", expectedKey2, key2)
}
file, header, err := r.FormFile("image")
if err != nil {
t.Fatal(err)
}
expectedFileName := "testImage.jpg"
if header.Filename != expectedFileName {
t.Fatalf("expected %s, got %s", expectedFileName, header.Filename)
}
defer file.Close()
content, err := ioutil.ReadAll(file)
if err != nil {
t.Fatal(err)
}
expectedContent := []byte("file content")
if !bytes.Equal(content, expectedContent) {
t.Fatalf("expected %s, got %s", string(expectedContent), string(content))
}
}
func TestSendRequestWithFileContent(t *testing.T) {
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
handleFileRequest(t, writer, request)
})
server := httptest.NewServer(handler)
defer server.Close()
client := NewHttpClient()
request := &HttpRequest{
RawURL: server.URL,
Method: "POST",
File: &File{Content: []byte("file content"), FieldName: "image", FileName: "testImage.jpg"},
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
}
resp, err := client.SendRequest(request)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
}
}
func TestSendRequestWithFilePath(t *testing.T) {
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
handleFileRequest(t, writer, request)
})
server := httptest.NewServer(handler)
defer server.Close()
tmpFile, err := ioutil.TempFile("", "testImage.jpg")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpFile.Name())
tmpFile.Write([]byte("file content"))
tmpFile.Close()
client := NewHttpClient()
request := &HttpRequest{
RawURL: server.URL,
Method: "POST",
File: &File{Path: tmpFile.Name(), FieldName: "image", FileName: "testImage.jpg"},
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
}
resp, err := client.SendRequest(request)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
}
}

View File

@@ -12,6 +12,7 @@ import (
"net/url"
"os"
"os/exec"
"runtime"
"strings"
"time"
@@ -242,11 +243,17 @@ func DownloadFile(filepath string, url string) error {
// IsPingConnected checks if can ping specified host or not.
func IsPingConnected(host string) bool {
cmd := exec.Command("ping", host, "-c", "1", "-W", "6")
cmd := exec.Command("ping", host, "-c", "4", "-W", "6")
if runtime.GOOS == "windows" {
cmd = exec.Command("ping", host, "-n", "4", "-w", "6")
}
err := cmd.Run()
if err != nil {
return false
}
return true
}

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
@@ -74,51 +75,34 @@ func setHeaderAndQueryParam(req *http.Request, reqUrl string, header, queryParam
}
func setHeaderAndQueryAndBody(req *http.Request, reqUrl string, header, queryParam, body interface{}) error {
err := setHeader(req, header)
if err != nil {
if err := setHeader(req, header); err != nil {
return err
}
err = setQueryParam(req, reqUrl, queryParam)
if err != nil {
} else if err = setQueryParam(req, reqUrl, queryParam); err != nil {
return err
}
if strings.Contains(req.Header.Get("Content-Type"), "multipart/form-data") || req.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
if formData, ok := queryParam.(url.Values); ok {
err = setBodyByte(req, []byte(formData.Encode()))
}
if formData, ok := queryParam.(map[string]string); ok {
postData := url.Values{}
for k, v := range formData {
postData.Set(k, v)
}
err = setBodyByte(req, []byte(postData.Encode()))
}
} else {
err = setBodyByte(req, body)
}
if err != nil {
} else if err = setBodyByte(req, body); err != nil {
return err
}
return nil
}
func setHeader(req *http.Request, header interface{}) error {
if header != nil {
switch v := header.(type) {
case map[string]string:
for k := range v {
req.Header.Add(k, v[k])
}
case http.Header:
for k, vv := range v {
for _, vvv := range vv {
req.Header.Add(k, vvv)
}
}
default:
return errors.New("header params type should be http.Header or map[string]string")
if header == nil {
return nil
}
switch v := header.(type) {
case map[string]string:
for k := range v {
req.Header.Add(k, v[k])
}
case http.Header:
for k, vv := range v {
for _, vvv := range vv {
req.Header.Add(k, vvv)
}
}
default:
return errors.New("header params type should be http.Header or map[string]string")
}
if host := req.Header.Get("Host"); host != "" {
@@ -138,19 +122,22 @@ func setUrl(req *http.Request, reqUrl string) error {
}
func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) error {
if queryParam == nil {
return nil
}
var values url.Values
if queryParam != nil {
switch v := queryParam.(type) {
case map[string]interface{}:
values = url.Values{}
for k := range v {
values.Set(k, fmt.Sprintf("%v", v[k]))
}
case url.Values:
values = v
default:
return errors.New("query params type should be url.Values or map[string]interface{}")
switch v := queryParam.(type) {
case map[string]interface{}:
values = url.Values{}
for k := range v {
values.Set(k, fmt.Sprintf("%v", v[k]))
}
case url.Values:
values = v
default:
return errors.New("query params type should be url.Values or map[string]interface{}")
}
// set url
@@ -171,14 +158,36 @@ func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) err
}
func setBodyByte(req *http.Request, body interface{}) error {
if body != nil {
switch b := body.(type) {
case []byte:
req.Body = ioutil.NopCloser(bytes.NewReader(b))
req.ContentLength = int64(len(b))
default:
return errors.New("body type should be []byte")
if body == nil {
return nil
}
var bodyReader *bytes.Reader
switch b := body.(type) {
case io.Reader:
buf := bytes.NewBuffer(nil)
if _, err := io.Copy(buf, b); err != nil {
return err
}
req.Body = ioutil.NopCloser(buf)
req.ContentLength = int64(buf.Len())
case []byte:
bodyReader = bytes.NewReader(b)
req.Body = ioutil.NopCloser(bodyReader)
req.ContentLength = int64(bodyReader.Len())
case map[string]interface{}:
values := url.Values{}
for k := range b {
values.Set(k, fmt.Sprintf("%v", b[k]))
}
bodyReader = bytes.NewReader([]byte(values.Encode()))
req.Body = ioutil.NopCloser(bodyReader)
req.ContentLength = int64(bodyReader.Len())
case url.Values:
bodyReader = bytes.NewReader([]byte(b.Encode()))
req.Body = ioutil.NopCloser(bodyReader)
req.ContentLength = int64(bodyReader.Len())
default:
return fmt.Errorf("invalid body type: %T", b)
}
return nil
}

View File

@@ -72,10 +72,3 @@ func TestTelnetConnected(t *testing.T) {
result2 := IsTelnetConnected("www.baidu.com", "123")
assert.Equal(false, result2)
}
// func TestDownloadFile(t *testing.T) {
// assert := internal.NewAssert(t, "TestDownloadFile")
// err := DownloadFile("./lancet_logo.jpg", "https://picx.zhimg.com/v2-fc82a4199749de9cfb71e32e54f489d3_720w.jpg?source=172ae18b")
// assert.IsNil(err)
// }

View File

@@ -8,22 +8,30 @@ import (
crand "crypto/rand"
"fmt"
"io"
"math"
"math/rand"
"time"
"unsafe"
"github.com/duke-git/lancet/mathutil"
)
const (
NUMERAL = "0123456789"
LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz"
UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
MaximumCapacity = math.MaxInt>>1 + 1
Numeral = "0123456789"
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
SymbolChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
)
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
// RandInt generate random int between [min, max).
func RandInt(min, max int) int {
if min == max {
return min
@@ -36,7 +44,23 @@ func RandInt(min, max int) int {
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 {
if length < 1 {
return []byte{}
@@ -46,48 +70,99 @@ func RandBytes(length int) []byte {
if _, err := io.ReadFull(crand.Reader, b); err != nil {
return nil
}
return b
}
// RandString generate random string
// RandString generate random alpha string of specified length.
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 {
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 {
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 {
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 {
return random(NUMERAL+LETTERS, length)
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)
// RandSymbolChar generate a random symbol char of specified length.
// symbol chars: !@#$%^&*()_+-=[]{}|;':\",./<>?.
func RandSymbolChar(length int) string {
return random(SymbolChars, 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))]
// nearestPowerOfTwo 返回一个大于等于cap的最近的2的整数次幂参考java8的hashmap的tableSizeFor函数
func nearestPowerOfTwo(cap int) int {
n := cap - 1
n |= n >> 1
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) {
uuid := make([]byte, 16)
@@ -101,3 +176,160 @@ func UUIdV4() (string, error) {
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}
// 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
}
// 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
// }

View File

@@ -105,3 +105,36 @@ func TestUUIdV4(t *testing.T) {
isUUiDV4 := regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`)
assert.Equal(true, isUUiDV4.MatchString(uuid))
}
func TestRandUniqueIntSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestRandUniqueIntSlice")
r1 := RandUniqueIntSlice(5, 0, 9)
assert.Equal(len(r1), 5)
if hasDuplicate(r1) {
t.Error("hasDuplicate int")
}
r2 := RandUniqueIntSlice(20, 0, 10)
assert.Equal(len(r2), 10)
if hasDuplicate(r2) {
t.Error("hasDuplicate int")
}
r3 := RandUniqueIntSlice(10, 20, 10)
assert.Equal(len(r3), 0)
r4 := RandUniqueIntSlice(0, 20, 10)
assert.Equal(len(r4), 0)
}
func hasDuplicate(arr []int) bool {
elements := make(map[int]bool)
for _, v := range arr {
if elements[v] {
return true
}
elements[v] = true
}
return false
}

View File

@@ -968,3 +968,16 @@ func AppendIfAbsent(slice interface{}, value interface{}) 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)
}

View File

@@ -624,3 +624,15 @@ func TestAppendIfAbsent(t *testing.T) {
assert.Equal([]string{"a", "b"}, AppendIfAbsent(str1, "a"))
assert.Equal([]string{"a", "b", "c"}, AppendIfAbsent(str1, "c"))
}
func TestJoin(t *testing.T) {
assert := internal.NewAssert(t, "TestJoin")
nums := []int{1, 2, 3, 4, 5}
result1 := Join(nums, ",")
result2 := Join(nums, "-")
assert.Equal("1,2,3,4,5", result1)
assert.Equal("1-2-3-4-5", result2)
}

View File

@@ -5,7 +5,8 @@
package strutil
import (
"reflect"
"errors"
"regexp"
"strings"
"unicode"
"unicode/utf8"
@@ -120,37 +121,45 @@ func UpperSnakeCase(s string) string {
// Before create substring in source string before position when char first appear
func Before(s, char string) string {
if s == "" || char == "" {
i := strings.Index(s, char)
if s == "" || char == "" || i == -1 {
return s
}
i := strings.Index(s, char)
return s[0:i]
}
// BeforeLast create substring in source string before position when char last appear
func BeforeLast(s, char string) string {
if s == "" || char == "" {
i := strings.LastIndex(s, char)
if s == "" || char == "" || i == -1 {
return s
}
i := strings.LastIndex(s, char)
return s[0:i]
}
// After create substring in source string after position when char first appear
func After(s, char string) string {
if s == "" || char == "" {
i := strings.Index(s, char)
if s == "" || char == "" || i == -1 {
return s
}
i := strings.Index(s, char)
return s[i+len(char):]
}
// AfterLast create substring in source string after position when char last appear
func AfterLast(s, char string) string {
if s == "" || char == "" {
i := strings.LastIndex(s, char)
if s == "" || char == "" || i == -1 {
return s
}
i := strings.LastIndex(s, char)
return s[i+len(char):]
}
@@ -341,10 +350,7 @@ func RemoveNonPrintable(str string) string {
// StringToBytes converts a string to byte slice without a memory allocation.
func StringToBytes(str string) (b []byte) {
sh := *(*reflect.StringHeader)(unsafe.Pointer(&str))
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
return *(*[]byte)(unsafe.Pointer(&str))
}
// BytesToString converts a byte slice to string without a memory allocation.
@@ -403,3 +409,153 @@ func IndexOffset(str string, substr string, idxFrom int) int {
return strings.Index(str[idxFrom:], substr) + idxFrom
}
// ReplaceWithMap returns a copy of `str`, which is replaced by a map in unordered way, case-sensitively.
func ReplaceWithMap(str string, replaces map[string]string) string {
for k, v := range replaces {
str = strings.ReplaceAll(str, k, v)
}
return str
}
// SplitAndTrim splits string `str` by a string `delimiter` to a slice,
// and calls Trim to every element of this slice. It ignores the elements
// which are empty after Trim.
func SplitAndTrim(str, delimiter string, characterMask ...string) []string {
result := make([]string, 0)
for _, v := range strings.Split(str, delimiter) {
v = Trim(v, characterMask...)
if v != "" {
result = append(result, v)
}
}
return result
}
var (
// DefaultTrimChars are the characters which are stripped by Trim* functions in default.
DefaultTrimChars = string([]byte{
'\t', // Tab.
'\v', // Vertical tab.
'\n', // New line (line feed).
'\r', // Carriage return.
'\f', // New page.
' ', // Ordinary space.
0x00, // NUL-byte.
0x85, // Delete.
0xA0, // Non-breaking space.
})
)
// Trim strips whitespace (or other characters) from the beginning and end of a string.
// The optional parameter `characterMask` specifies the additional stripped characters.
func Trim(str string, characterMask ...string) string {
trimChars := DefaultTrimChars
if len(characterMask) > 0 {
trimChars += characterMask[0]
}
return strings.Trim(str, trimChars)
}
// HideString hide some chars in source string with param `replaceChar`.
// replace range is origin[start : end]. [start, end)
func HideString(origin string, start, end int, replaceChar string) string {
size := len(origin)
if start > size-1 || start < 0 || end < 0 || start > end {
return origin
}
if end > size {
end = size
}
if replaceChar == "" {
return origin
}
startStr := origin[0:start]
endStr := origin[end:size]
replaceSize := end - start
replaceStr := strings.Repeat(replaceChar, replaceSize)
return startStr + replaceStr + endStr
}
// ContainsAll return true if target string contains all the substrs.
func ContainsAll(str string, substrs []string) bool {
for _, v := range substrs {
if !strings.Contains(str, v) {
return false
}
}
return true
}
// ContainsAny return true if target string contains any one of the substrs.
func ContainsAny(str string, substrs []string) bool {
for _, v := range substrs {
if strings.Contains(str, v) {
return true
}
}
return false
}
var (
whitespaceRegexMatcher *regexp.Regexp = regexp.MustCompile(`\s`)
mutiWhitespaceRegexMatcher *regexp.Regexp = regexp.MustCompile(`[[:space:]]{2,}|[\s\p{Zs}]{2,}`)
)
// RemoveWhiteSpace remove whitespace characters from a string.
// when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.
func RemoveWhiteSpace(str string, repalceAll bool) string {
if repalceAll && str != "" {
return strings.Join(strings.Fields(str), "")
} else if str != "" {
str = mutiWhitespaceRegexMatcher.ReplaceAllString(str, " ")
str = whitespaceRegexMatcher.ReplaceAllString(str, " ")
}
return strings.TrimSpace(str)
}
// 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
}

View File

@@ -207,6 +207,7 @@ func TestBefore(t *testing.T) {
assert := internal.NewAssert(t, "TestBefore")
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", "test"))
}
@@ -215,16 +216,42 @@ func TestBeforeLast(t *testing.T) {
assert := internal.NewAssert(t, "TestBeforeLast")
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/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) {
assert := internal.NewAssert(t, "TestAfter")
assert.Equal("lancet", After("lancet", ""))
assert.Equal("lancet", After("lancet", "abcdef"))
assert.Equal("test/lancet", After("github.com/test/lancet", "/"))
assert.Equal("/lancet", After("github.com/test/lancet", "test"))
}
@@ -233,6 +260,7 @@ func TestAfterLast(t *testing.T) {
assert := internal.NewAssert(t, "TestAfterLast")
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", "test"))
assert.Equal("/lancet", AfterLast("github.com/test/test/lancet", "test"))
@@ -386,3 +414,94 @@ func TestIndexOffset(t *testing.T) {
assert.Equal(IndexOffset(str, "d", len(str)), -1)
assert.Equal(IndexOffset(str, "f", -1), -1)
}
func TestReplaceWithMap(t *testing.T) {
assert := internal.NewAssert(t, "TestReplaceWithMap")
str := "ac ab ab ac"
replaces := map[string]string{
"a": "1",
"b": "2",
}
assert.Equal(str, "ac ab ab ac")
assert.Equal(ReplaceWithMap(str, replaces), "1c 12 12 1c")
}
func TestTrim(t *testing.T) {
assert := internal.NewAssert(t, "TestTrim")
str1 := "$ ab cd $ "
assert.Equal("$ ab cd $", Trim(str1))
assert.Equal("ab cd", Trim(str1, "$"))
assert.Equal("abcd", Trim("\nabcd"))
}
func TestSplitAndTrim(t *testing.T) {
assert := internal.NewAssert(t, "TestTrim")
str := " a,b, c,d,$1 "
result1 := SplitAndTrim(str, ",")
result2 := SplitAndTrim(str, ",", "$")
assert.Equal([]string{"a", "b", "c", "d", "$1"}, result1)
assert.Equal([]string{"a", "b", "c", "d", "1"}, result2)
}
func TestHideString(t *testing.T) {
assert := internal.NewAssert(t, "TestTrim")
str := "13242658976"
assert.Equal("13242658976", HideString(str, 0, -1, "*"))
assert.Equal("13242658976", HideString(str, 0, 0, "*"))
assert.Equal("****2658976", HideString(str, 0, 4, "*"))
assert.Equal("13242658976", HideString(str, 3, 3, "*"))
assert.Equal("132*2658976", HideString(str, 3, 4, "*"))
assert.Equal("132****8976", HideString(str, 3, 7, "*"))
assert.Equal("1324265****", HideString(str, 7, 11, "*"))
assert.Equal("1324265****", HideString(str, 7, 100, "*"))
assert.Equal("13242658976", HideString(str, 100, 100, "*"))
}
func TestContainsAll(t *testing.T) {
assert := internal.NewAssert(t, "TestContainsAll")
assert.Equal(true, ContainsAll("hello world", []string{"hello", "world"}))
assert.Equal(true, ContainsAll("hello world", []string{""}))
assert.Equal(false, ContainsAll("hello world", []string{"hello", "abc"}))
}
func TestContainsAny(t *testing.T) {
assert := internal.NewAssert(t, "TestContainsAny")
assert.Equal(true, ContainsAny("hello world", []string{"hello", "world"}))
assert.Equal(true, ContainsAny("hello world", []string{"hello", "abc"}))
assert.Equal(false, ContainsAny("hello world", []string{"123", "abc"}))
}
func TestRemoveWhiteSpace(t *testing.T) {
assert := internal.NewAssert(t, "TestRemoveWhiteSpace")
str := " hello \r\n \t world"
assert.Equal("", RemoveWhiteSpace("", true))
assert.Equal("helloworld", RemoveWhiteSpace(str, true))
assert.Equal("hello world", RemoveWhiteSpace(str, false))
}
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"))
}

View File

@@ -45,7 +45,7 @@ func TestExecCommand(t *testing.T) {
assert := internal.NewAssert(t, "TestExecCommand")
// linux or mac
stdout, stderr, err := ExecCommand("ls", WithForeground())
stdout, stderr, err := ExecCommand("ls")
t.Log("std out: ", stdout)
t.Log("std err: ", stderr)
assert.Equal("", stderr)

View File

@@ -16,18 +16,26 @@ import (
)
var (
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
emailMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
base64Matcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
emailMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
base64Matcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
base64URLMatcher *regexp.Regexp = regexp.MustCompile(`^([A-Za-z0-9_-]{4})*([A-Za-z0-9_-]{2}(==)?|[A-Za-z0-9_-]{3}=?)?$`)
binMatcher *regexp.Regexp = regexp.MustCompile(`^(0b)?[01]+$`)
hexMatcher *regexp.Regexp = regexp.MustCompile(`^(#|0x|0X)?[0-9a-fA-F]+$`)
visaMatcher *regexp.Regexp = regexp.MustCompile(`^4[0-9]{12}(?:[0-9]{3})?$`)
masterCardMatcher *regexp.Regexp = regexp.MustCompile(`^5[1-5][0-9]{14}$`)
americanExpressMatcher *regexp.Regexp = regexp.MustCompile(`^3[47][0-9]{13}$`)
unionPay *regexp.Regexp = regexp.MustCompile("^62[0-5]\\d{13,16}$")
chinaUnionPay *regexp.Regexp = regexp.MustCompile(`^62[0-9]{14,17}$`)
)
// IsAlpha checks if the string contains only letters (a-zA-Z)
@@ -362,3 +370,59 @@ func IsPrintable(str string) bool {
}
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)
}

View File

@@ -448,3 +448,90 @@ func TestIsPrintable(t *testing.T) {
assert.Equal(true, IsPrintable("😄"))
assert.Equal(false, IsPrintable("\u0000"))
}
func TestIsBin(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsBin")
assert.Equal(true, IsBin("0101"))
assert.Equal(true, IsBin("0b1101"))
assert.Equal(false, IsBin("b1101"))
assert.Equal(false, IsBin("1201"))
assert.Equal(false, IsBin(""))
}
func TestIsHex(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsHex")
assert.Equal(true, IsHex("ABCDE"))
assert.Equal(true, IsHex("abcde"))
assert.Equal(true, IsHex("0xabcde"))
assert.Equal(true, IsHex("0Xabcde"))
assert.Equal(true, IsHex("#abcde"))
assert.Equal(false, IsHex("cdfeg"))
assert.Equal(false, IsHex("0xcdfeg"))
assert.Equal(false, IsHex(""))
}
func TestIsBase64URL(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsBase64URL")
assert.Equal(true, IsBase64URL("SAGsbG8sIHdvcmxkIQ"))
assert.Equal(true, IsBase64URL("SAGsbG8sIHdvcmxkIQ=="))
assert.Equal(false, IsBase64URL("SAGsbG8sIHdvcmxkIQ="))
assert.Equal(false, IsBase64URL("SAGsbG8sIHdvcmxkIQ==="))
// assert.Equal(false, IsBase64URL(""))
}
func TestIsJWT(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsJWT")
assert.Equal(true, IsJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibWVzc2FnZSI6IlB1dGluIGlzIGFic29sdXRlIHNoaXQiLCJpYXQiOjE1MTYyMzkwMjJ9.wkLWA5GtCpWdxNOrRse8yHZgORDgf8TpJp73WUQb910"))
assert.Equal(false, IsJWT("abc"))
}
func TestIsVisa(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsVisa")
assert.Equal(true, IsVisa("4111111111111111"))
assert.Equal(false, IsVisa("123"))
}
func TestIsMasterCard(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsMasterCard")
assert.Equal(true, IsMasterCard("5425233430109903"))
assert.Equal(false, IsMasterCard("4111111111111111"))
}
func TestIsAmericanExpress(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsAmericanExpress")
assert.Equal(true, IsAmericanExpress("342883359122187"))
assert.Equal(false, IsAmericanExpress("3782822463100007"))
}
func TestIsUnionPay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsUnionPay")
assert.Equal(true, IsUnionPay("6221263430109903"))
assert.Equal(false, IsUnionPay("3782822463100007"))
}
func TestIsChinaUnionPay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsChinaUnionPay")
assert.Equal(true, IsChinaUnionPay("6250941006528599"))
assert.Equal(false, IsChinaUnionPay("3782822463100007"))
}