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

Compare commits

..

10 Commits

Author SHA1 Message Date
dudaodong
f3d73899b1 release v1.3.5 2022-12-15 16:36:15 +08:00
dudaodong
d4a20b239a add new function 2022-12-15 16:35:33 +08:00
dudaodong
4c28431451 fix: fix lint issue 2022-12-15 16:31:04 +08:00
dudaodong
168ed096c7 fix: fix ExecCommand bug forwindows 2022-12-15 16:29:36 +08:00
dudaodong
a060769635 clean code 2022-12-15 16:27:21 +08:00
dudaodong
0a99492cf6 feat: add IsGBK 2022-12-15 16:21:09 +08:00
dudaodong
fb3de03f37 clean document 2022-12-15 16:13:32 +08:00
dudaodong
43c2fd2a22 feat: add UpperKebabCase/UpperSnakeCase 2022-12-15 16:05:02 +08:00
dudaodong
279d0754ba release v1.3.4 2022-11-17 16:14:42 +08:00
dudaodong
f133b32faa fix: issue#62: fix ZipSlip bug 2022-11-17 16:14:03 +08:00
30 changed files with 667 additions and 235 deletions

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.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-1.3.5-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)
@@ -350,12 +350,14 @@ import "github.com/duke-git/lancet/strutil"
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Capitalize)
- [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)
- [LowerFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#PadStart)
- [Reverse](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Reverse)
- [SnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SnakeCase)
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperSnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Unwrap)
@@ -413,6 +415,7 @@ import "github.com/duke-git/lancet/validator"
- [IsUrl](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsWeakPassword)
- [IsZeroValue](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsZeroValue)
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsGBK)
## 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.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-1.3.5-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)
@@ -349,12 +349,14 @@ import "github.com/duke-git/lancet/strutil"
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Capitalize)
- [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)
- [LowerFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadStart)
- [Reverse](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Reverse)
- [SnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SnakeCase)
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperSnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Unwrap)
@@ -412,6 +414,7 @@ import "github.com/duke-git/lancet/validator"
- [IsUrl](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsWeakPassword)
- [IsZeroValue](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsZeroValue)
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsGBK)
## 如何贡献代码

View File

@@ -19,12 +19,14 @@ import (
<div STYLE="page-break-after: always;"></div>
## Index
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)

View File

@@ -21,25 +21,19 @@ import (
## 目录
- [Convertor](#convertor)
- [源码:](#源码)
- [用法:](#用法)
- [目录](#目录)
- [文档](#文档)
- [<span id="ColorHexToRGB">ColorHexToRGB</span>](#colorhextorgb)
- [<span id="ColorRGBToHex">ColorRGBToHex</span>](#colorrgbtohex)
- [<span id="ToBool">ToBool</span>](#tobool)
- [<span id="ToBytes">ToBytes</span>](#tobytes)
- [<span id="ToChar">ToChar</span>](#tochar)
- [<span id="ToChannel">ToChannel</span>](#tochannel)
- [<span id="ToFloat">ToFloat</span>](#tofloat)
- [<span id="ToInt">ToInt</span>](#toint)
- [<span id="ToJson">ToJson</span>](#tojson)
- [<span id="ToString">ToString</span>](#tostring)
- [<span id="StructToMap">StructToMap</span>](#structtomap)
- [<span id="EncodeByte">EncodeByte</span>](#encodebyte)
- [<span id="DecodeByte">DecodeByte</span>](#decodebyte)
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
<div STYLE="page-break-after: always;"></div>

View File

@@ -47,7 +47,6 @@ import (
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)
- [HmacSha512](#HmacSha512)
- [Md5String](#Md5String)
- [Md5File](#Md5File)
- [Sha1](#Sha1)

View File

@@ -33,7 +33,6 @@ import (
- [AesOfbDecrypt](#AesOfbDecrypt)
- [Base64StdEncode](#Base64StdEncode)
- [Base64StdDecode](#Base64StdDecode)
- [DesEcbEncrypt](#DesEcbEncrypt)
- [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt)
@@ -43,7 +42,6 @@ import (
- [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)

View File

@@ -28,7 +28,6 @@ import (
- [BeginOfWeek](#BeginOfWeek)
- [BeginOfMonth](#BeginOfMonth)
- [BeginOfYear](#BeginOfYear)
- [EndOfMinute](#EndOfMinute)
- [EndOfHour](#EndOfHour)
- [EndOfDay](#EndOfDay)

View File

@@ -28,7 +28,6 @@ import (
- [BeginOfWeek](#BeginOfWeek)
- [BeginOfMonth](#BeginOfMonth)
- [BeginOfYear](#BeginOfYear)
- [EndOfMinute](#EndOfMinute)
- [EndOfHour](#EndOfHour)
- [EndOfDay](#EndOfDay)

View File

@@ -21,7 +21,6 @@ import (
## Index
- [ClearFile](#ClearFile)
- [CreateFile](#CreateFile)
- [CreateDir](#CreateDir)
- [CopyFile](#CopyFile)
- [FileMode](#FileMode)

View File

@@ -28,7 +28,6 @@ import (
- [IsExist](#IsExist)
- [IsLink](#IsLink)
- [IsDir](#IsDir)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)

View File

@@ -37,7 +37,6 @@ import (
- [SendRequest](#SendRequest)
- [DecodeResponse](#DecodeResponse)
- [StructToUrlValues](#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](#HttpPost)

View File

@@ -36,7 +36,6 @@ import (
- [SendRequest](#SendRequest)
- [DecodeResponse](#DecodeResponse)
- [StructToUrlValues](#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](#HttpPost)

View File

@@ -26,7 +26,6 @@ import (
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)

View File

@@ -26,7 +26,6 @@ import (
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)

View File

@@ -39,7 +39,6 @@ import (
- [FindLast](#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [GroupBy](#GroupBy)
- [IntSlice](#IntSlice)
- [InterfaceSlice](#InterfaceSlice)

View File

@@ -39,7 +39,6 @@ import (
- [FindLast](#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [GroupBy](#GroupBy)
- [IntSlice](#IntSlice)
- [InterfaceSlice](#InterfaceSlice)

View File

@@ -28,14 +28,15 @@ import (
- [Capitalize](#Capitalize)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
- [UpperKebabCase](#UpperKebabCase)
- [LowerFirst](#LowerFirst)
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [ReverseStr](#ReverseStr)
- [Reverse](#Reverse)
- [SnakeCase](#SnakeCase)
- [UpperSnakeCase](#UpperSnakeCase)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap)
- [SplitEx](#SplitEx)
@@ -169,7 +170,7 @@ func main() {
### <span id="CamelCase">CamelCase</span>
<p>Covert string to camelCase string.</p>
<p>Coverts string to camelCase string, non letters and numbers will be ignored.</p>
<b>Signature:</b>
@@ -196,7 +197,9 @@ func main() {
s4 := strutil.CamelCase("foo bar")
fmt.Println(s4) //fooBar
}
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s4) //foo11Bar
```
@@ -261,7 +264,7 @@ func main() {
### <span id="KebabCase">KebabCase</span>
<p>Covert string to kebab-case.</p>
<p>KebabCase covert string to kebab-case, non letters and numbers will be ignored.</p>
<b>Signature:</b>
@@ -287,12 +290,44 @@ func main() {
fmt.Println(s3) //foo-bar
s4 := strutil.KebabCase("__FOO_BAR__")
fmt.Println(s4) //f-o-o-b-a-r
fmt.Println(s4) //foo-bar
}
```
### <span id="UpperKebabCase">UpperKebabCase</span>
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
<b>Signature:</b>
```go
func KebabCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
s1 := strutil.UpperKebabCase("Foo Bar-")
fmt.Println(s1) //FOO-BAR
s2 := strutil.UpperKebabCase("foo_Bar")
fmt.Println(s2) //FOO-BAR
s3 := strutil.UpperKebabCase("fooBar")
fmt.Println(s3) //FOO-BAR
s4 := strutil.UpperKebabCase("__FOO_BAR__")
fmt.Println(s4) //FOO-BAR
}
```
### <span id="LowerFirst">LowerFirst</span>
<p>Convert the first character of string to lower case.</p>
@@ -456,9 +491,8 @@ func main() {
```
### <span id="SnakeCase">SnakeCase</span>
<p>Covert string to snake_case.</p>
<p>Coverts string to snake_case, non letters and numbers will be ignored.</p>
<b>Signature:</b>
@@ -484,14 +518,48 @@ func main() {
fmt.Println(s3) //foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__")
fmt.Println(s4) //f_o_o_b_a_r
fmt.Println(s4) //foo_bar
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //foo_1_1_bar
}
```
### <span id="UpperSnakeCase">UpperSnakeCase</span>
<p>Coverts string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
<b>Signature:</b>
```go
func SnakeCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
s1 := strutil.UpperSnakeCase("Foo Bar-")
fmt.Println(s1) //FOO_BAR
s2 := strutil.UpperSnakeCase("foo_Bar")
fmt.Println(s2) //FOO_BAR
s3 := strutil.UpperSnakeCase("fooBar")
fmt.Println(s3) //FOO_BAR
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
fmt.Println(s4) //FOO_BAR
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //FOO_1_1_BAR
}
```
### <span id="Wrap">Wrap</span>

View File

@@ -28,14 +28,15 @@ import (
- [Capitalize](#Capitalize)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
- [UpperKebabCase](#UpperKebabCase)
- [LowerFirst](#LowerFirst)
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [ReverseStr](#ReverseStr)
- [Reverse](#Reverse)
- [SnakeCase](#SnakeCase)
- [UpperSnakeCase](#UpperSnakeCase)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap)
- [SplitEx](#SplitEx)
@@ -170,7 +171,7 @@ func main() {
### <span id="CamelCase">CamelCase</span>
<p>将字符串转换为驼峰式字符串</p>
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略</p>
<b>函数签名:</b>
@@ -197,6 +198,9 @@ func main() {
s4 := strutil.CamelCase("foo bar")
fmt.Println(s4) //fooBar
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s4) //foo11Bar
}
```
@@ -260,9 +264,8 @@ func main() {
```
### <span id="KebabCase">KebabCase</span>
<p>将字符串转换为kebab-case</p>
<p>将字符串转换为kebab-case, 非字母和数字会被忽略</p>
<b>函数签名:</b>
@@ -288,12 +291,43 @@ func main() {
fmt.Println(s3) //foo-bar
s4 := strutil.KebabCase("__FOO_BAR__")
fmt.Println(s4) //f-o-o-b-a-r
fmt.Println(s4) //foo-bar
}
```
### <span id="UpperKebabCase">UpperKebabCase</span>
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略</p>
<b>函数签名:</b>
```go
func KebabCase(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
s1 := strutil.UpperKebabCase("Foo Bar-")
fmt.Println(s1) //FOO-BAR
s2 := strutil.UpperKebabCase("foo_Bar")
fmt.Println(s2) //FOO-BAR
s3 := strutil.UpperKebabCase("fooBar")
fmt.Println(s3) //FOO-BAR
s4 := strutil.UpperKebabCase("__FOO_BAR__")
fmt.Println(s4) //FOO-BAR
}
```
### <span id="LowerFirst">LowerFirst</span>
<p>将字符串的第一个字符转换为小写</p>
@@ -457,9 +491,8 @@ func main() {
```
### <span id="SnakeCase">SnakeCase</span>
<p>将字符串转换为snake_case形式</p>
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略</p>
<b>函数签名:</b>
@@ -485,14 +518,48 @@ func main() {
fmt.Println(s3) //foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__")
fmt.Println(s4) //f_o_o_b_a_r
fmt.Println(s4) //foo_bar
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //foo_1_1_bar
}
```
### <span id="UpperSnakeCase">UpperSnakeCase</span>
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略</p>
<b>函数签名:</b>
```go
func SnakeCase(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/strutil"
)
func main() {
s1 := strutil.UpperSnakeCase("Foo Bar-")
fmt.Println(s1) //FOO_BAR
s2 := strutil.UpperSnakeCase("foo_Bar")
fmt.Println(s2) //FOO_BAR
s3 := strutil.UpperSnakeCase("fooBar")
fmt.Println(s3) //FOO_BAR
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
fmt.Println(s4) //FOO_BAR
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //FOO_1_1_BAR
}
```
### <span id="Wrap">Wrap</span>

View File

@@ -34,7 +34,6 @@ import (
- [IsCreditCard](#IsCreditCard)
- [IsDns](#IsDns)
- [IsEmail](#IsEmail)
- [IsEmptyString](#IsEmptyString)
- [IsFloatStr](#IsFloatStr)
- [IsNumberStr](#IsNumberStr)
@@ -48,7 +47,7 @@ import (
- [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
<div STYLE="page-break-after: always;"></div>
@@ -820,7 +819,34 @@ func main() {
### <span id="IsGBK">IsGBK</span>
<p>Checks if data encoding is gbk(Chinese character internal code extension specification). this function is implemented by whether double bytes fall within the encoding range of gbk,while each byte of utf-8 encoding format falls within the encoding range of gbk.Therefore, utf8.valid() should be called first to check whether it is not utf-8 encoding and then call IsGBK() to check gbk encoding. like the example.</p>
<b>Signature:</b>
```go
func IsGBK(data []byte) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/validator"
)
func main() {
data := []byte("你好")
// check utf8 first
if utf8.Valid(data) {
fmt.Println("data encoding is utf-8")
}else if(validator.IsGBK(data)) {
fmt.Println("data encoding is GBK")
}
fmt.Println("data encoding is unknown")
}
```

View File

@@ -34,7 +34,6 @@ import (
- [IsCreditCard](#IsCreditCard)
- [IsDns](#IsDns)
- [IsEmail](#IsEmail)
- [IsEmptyString](#IsEmptyString)
- [IsFloatStr](#IsFloatStr)
- [IsNumberStr](#IsNumberStr)
@@ -48,7 +47,7 @@ import (
- [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
<div STYLE="page-break-after: always;"></div>
@@ -822,6 +821,33 @@ func main() {
### <span id="IsGBK">IsGBK</span>
<p>检查数据编码是否为gbk汉字内部代码扩展规范。该函数的实现取决于双字节是否在gbk的编码范围内而utf-8编码格式的每个字节都在gbk编码范围内。因此应该首先调用utf8.valid检查它是否是utf-8编码然后调用IsGBK检查gbk编码。如示例所示。</p>
<b>函数签名:</b>
```go
func IsGBK(data []byte) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/validator"
)
func main() {
data := []byte("你好")
// 先检查utf8编码
if utf8.Valid(data) {
fmt.Println("data encoding is utf-8")
}else if(validator.IsGBK(data)) {
fmt.Println("data encoding is GBK")
}
fmt.Println("data encoding is unknown")
}
```

View File

@@ -8,6 +8,7 @@ import (
"archive/zip"
"bufio"
"errors"
"fmt"
"io"
"io/fs"
"io/ioutil"
@@ -220,7 +221,11 @@ func UnZip(zipFile string, destPath string) error {
defer zipReader.Close()
for _, f := range zipReader.File {
path := filepath.Join(destPath, f.Name)
//issue#62: fix ZipSlip bug
path, err := safeFilepathJoin(destPath, f.Name)
if err != nil {
return err
}
if f.FileInfo().IsDir() {
os.MkdirAll(path, os.ModePerm)
} else {
@@ -249,6 +254,17 @@ func UnZip(zipFile string, destPath string) error {
return nil
}
func safeFilepathJoin(path1, path2 string) (string, error) {
relPath, err := filepath.Rel(".", path2)
if err != nil || strings.HasPrefix(relPath, "..") {
return "", fmt.Errorf("(zipslip) filepath is unsafe %q: %v", path2, err)
}
if path1 == "" {
path1 = "."
}
return filepath.Join(path1, filepath.Join("/", relPath)), nil
}
// IsLink checks if a file is symbol link or not
func IsLink(path string) bool {
fi, err := os.Lstat(path)

2
go.mod
View File

@@ -1,3 +1,5 @@
module github.com/duke-git/lancet
go 1.16
require golang.org/x/text v0.5.0

25
go.sum Normal file
View File

@@ -0,0 +1,25 @@
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -5,53 +5,41 @@
package strutil
import (
"regexp"
"strings"
"unicode"
"unicode/utf8"
)
// CamelCase covert string to camelCase string.
// non letters and numbers will be ignored
// eg. "Foo-#1😄$_%^&*(1bar" => "foo11Bar"
func CamelCase(s string) string {
if len(s) == 0 {
return ""
}
var builder strings.Builder
res := ""
blankSpace := " "
regex, _ := regexp.Compile("[-_&]+")
ss := regex.ReplaceAllString(s, blankSpace)
for i, v := range strings.Split(ss, blankSpace) {
vv := []rune(v)
strs := splitIntoStrings(s, false)
for i, str := range strs {
if i == 0 {
if vv[i] >= 65 && vv[i] <= 96 {
vv[0] += 32
}
res += string(vv)
builder.WriteString(strings.ToLower(str))
} else {
res += Capitalize(v)
builder.WriteString(Capitalize(str))
}
}
return res
return builder.String()
}
// Capitalize converts the first character of a string to upper case and the remaining to lower case.
func Capitalize(s string) string {
if len(s) == 0 {
return ""
}
out := make([]rune, len(s))
result := make([]rune, len(s))
for i, v := range s {
if i == 0 {
out[i] = unicode.ToUpper(v)
result[i] = unicode.ToUpper(v)
} else {
out[i] = unicode.ToLower(v)
result[i] = unicode.ToLower(v)
}
}
return string(out)
return string(result)
}
// UpperFirst converts the first character of string to upper case.
@@ -117,47 +105,35 @@ func PadStart(source string, size int, padStr string) string {
}
// KebabCase covert string to kebab-case
// non letters and numbers will be ignored
// eg. "Foo-#1😄$_%^&*(1bar" => "foo-1-1-bar"
func KebabCase(s string) string {
if len(s) == 0 {
return ""
}
result := splitIntoStrings(s, false)
return strings.Join(result, "-")
}
regex := regexp.MustCompile(`[\W|_]+`)
blankSpace := " "
match := regex.ReplaceAllString(s, blankSpace)
rs := strings.Split(match, blankSpace)
var res []string
for _, v := range rs {
splitWords := splitWordsToLower(v)
if len(splitWords) > 0 {
res = append(res, splitWords...)
}
}
return strings.Join(res, "-")
// UpperKebabCase covert string to upper KEBAB-CASE
// non letters and numbers will be ignored
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO-1-1-BAR"
func UpperKebabCase(s string) string {
result := splitIntoStrings(s, true)
return strings.Join(result, "-")
}
// SnakeCase covert string to snake_case
// non letters and numbers will be ignored
// eg. "Foo-#1😄$_%^&*(1bar" => "foo_1_1_bar"
func SnakeCase(s string) string {
if len(s) == 0 {
return ""
}
result := splitIntoStrings(s, false)
return strings.Join(result, "_")
}
regex := regexp.MustCompile(`[\W|_]+`)
blankSpace := " "
match := regex.ReplaceAllString(s, blankSpace)
rs := strings.Split(match, blankSpace)
var res []string
for _, v := range rs {
splitWords := splitWordsToLower(v)
if len(splitWords) > 0 {
res = append(res, splitWords...)
}
}
return strings.Join(res, "_")
// UpperSnakeCase covert string to upper SNAKE_CASE
// non letters and numbers will be ignored
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO_1_1_BAR"
func UpperSnakeCase(s string) string {
result := splitIntoStrings(s, true)
return strings.Join(result, "_")
}
// Before create substring in source string before position when char first appear

View File

@@ -1,40 +1,98 @@
package strutil
import "strings"
import "unicode"
// splitWordsToLower split a string into worlds by uppercase char
func splitWordsToLower(s string) []string {
var res []string
func splitIntoStrings(s string, upperCase bool) []string {
var runes [][]rune
lastCharType := 0
charType := 0
upperIndexes := upperIndex(s)
l := len(upperIndexes)
if upperIndexes == nil || l == 0 {
if s != "" {
res = append(res, s)
// split into fields based on type of unicode character
for _, r := range s {
switch true {
case isLower(r):
charType = 1
case isUpper(r):
charType = 2
case isDigit(r):
charType = 3
default:
charType = 4
}
return res
}
for i := 0; i < l; i++ {
if i < l-1 {
res = append(res, strings.ToLower(s[upperIndexes[i]:upperIndexes[i+1]]))
if charType == lastCharType {
runes[len(runes)-1] = append(runes[len(runes)-1], r)
} else {
res = append(res, strings.ToLower(s[upperIndexes[i]:]))
runes = append(runes, []rune{r})
}
}
return res
}
// upperIndex get a int slice which elements are all the uppercase char index of a string
func upperIndex(s string) []int {
var res []int
for i := 0; i < len(s); i++ {
if 64 < s[i] && s[i] < 91 {
res = append(res, i)
}
}
if len(s) > 0 && res != nil && res[0] != 0 {
res = append([]int{0}, res...)
lastCharType = charType
}
return res
for i := 0; i < len(runes)-1; i++ {
if isUpper(runes[i][0]) && isLower(runes[i+1][0]) {
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
runes[i] = runes[i][:len(runes[i])-1]
}
}
// filter all none letters and none digit
var result []string
for _, rs := range runes {
if len(rs) > 0 && (unicode.IsLetter(rs[0]) || isDigit(rs[0])) {
if upperCase {
result = append(result, string(toUpperAll(rs)))
} else {
result = append(result, string(toLowerAll(rs)))
}
}
}
return result
}
// isDigit checks if a character is digit ('0' to '9')
func isDigit(r rune) bool {
return r >= '0' && r <= '9'
}
// isLower checks if a character is lower case ('a' to 'z')
func isLower(r rune) bool {
return r >= 'a' && r <= 'z'
}
// isUpper checks if a character is upper case ('A' to 'Z')
func isUpper(r rune) bool {
return r >= 'A' && r <= 'Z'
}
// toLower converts a character 'A' to 'Z' to its lower case
func toLower(r rune) rune {
if r >= 'A' && r <= 'Z' {
return r + 32
}
return r
}
// toLowerAll converts a character 'A' to 'Z' to its lower case
func toLowerAll(rs []rune) []rune {
for i := range rs {
rs[i] = toLower(rs[i])
}
return rs
}
// toUpper converts a character 'a' to 'z' to its upper case
func toUpper(r rune) rune {
if r >= 'a' && r <= 'z' {
return r - 32
}
return r
}
// toUpperAll converts a character 'a' to 'z' to its upper case
func toUpperAll(rs []rune) []rune {
for i := range rs {
rs[i] = toUpper(rs[i])
}
return rs
}

View File

@@ -9,67 +9,163 @@ import (
func TestCamelCase(t *testing.T) {
assert := internal.NewAssert(t, "TestCamelCase")
assert.Equal("fooBar", CamelCase("foo_bar"))
assert.Equal("fooBar", CamelCase("Foo-Bar"))
assert.Equal("fooBar", CamelCase("Foo&bar"))
assert.Equal("fooBar", CamelCase("foo bar"))
cases := map[string]string{
"": "",
"foobar": "foobar",
"&FOO:BAR$BAZ": "fooBarBaz",
"fooBar": "fooBar",
"FOObar": "foObar",
"$foo%": "foo",
" $#$Foo 22 bar ": "foo22Bar",
"Foo-#1😄$_%^&*(1bar": "foo11Bar",
}
assert.NotEqual("FooBar", CamelCase("foo_bar"))
for k, v := range cases {
assert.Equal(v, CamelCase(k))
}
}
func TestCapitalize(t *testing.T) {
assert := internal.NewAssert(t, "TestCapitalize")
assert.Equal("Foo", Capitalize("foo"))
assert.Equal("Foo", Capitalize("Foo"))
assert.Equal("Foo", Capitalize("Foo"))
cases := map[string]string{
"": "",
"Foo": "Foo",
"_foo": "_foo",
"foobar": "Foobar",
"fooBar": "Foobar",
"foo Bar": "Foo bar",
"foo-bar": "Foo-bar",
"$foo%": "$foo%",
}
assert.NotEqual("foo", Capitalize("Foo"))
for k, v := range cases {
assert.Equal(v, Capitalize(k))
}
}
func TestKebabCase(t *testing.T) {
assert := internal.NewAssert(t, "TestKebabCase")
assert.Equal("foo-bar", KebabCase("Foo Bar-"))
assert.Equal("foo-bar", KebabCase("foo_Bar"))
assert.Equal("foo-bar", KebabCase("fooBar"))
assert.Equal("f-o-o-b-a-r", KebabCase("__FOO_BAR__"))
cases := map[string]string{
"": "",
"foo-bar": "foo-bar",
"--Foo---Bar-": "foo-bar",
"Foo Bar-": "foo-bar",
"foo_Bar": "foo-bar",
"fooBar": "foo-bar",
"FOOBAR": "foobar",
"FOO_BAR": "foo-bar",
"__FOO_BAR__": "foo-bar",
"$foo@Bar": "foo-bar",
" $#$Foo 22 bar ": "foo-22-bar",
"Foo-#1😄$_%^&*(1bar": "foo-1-1-bar",
}
assert.NotEqual("foo_bar", KebabCase("fooBar"))
for k, v := range cases {
assert.Equal(v, KebabCase(k))
}
}
func TestUpperKebabCase(t *testing.T) {
assert := internal.NewAssert(t, "TestUpperKebabCase")
cases := map[string]string{
"": "",
"foo-bar": "FOO-BAR",
"--Foo---Bar-": "FOO-BAR",
"Foo Bar-": "FOO-BAR",
"foo_Bar": "FOO-BAR",
"fooBar": "FOO-BAR",
"FOOBAR": "FOOBAR",
"FOO_BAR": "FOO-BAR",
"__FOO_BAR__": "FOO-BAR",
"$foo@Bar": "FOO-BAR",
" $#$Foo 22 bar ": "FOO-22-BAR",
"Foo-#1😄$_%^&*(1bar": "FOO-1-1-BAR",
}
for k, v := range cases {
assert.Equal(v, UpperKebabCase(k))
}
}
func TestSnakeCase(t *testing.T) {
assert := internal.NewAssert(t, "TestSnakeCase")
assert.Equal("foo_bar", SnakeCase("Foo Bar-"))
assert.Equal("foo_bar", SnakeCase("foo_Bar"))
assert.Equal("foo_bar", SnakeCase("fooBar"))
assert.Equal("f_o_o_b_a_r", SnakeCase("__FOO_BAR__"))
assert.Equal("a_bbc_s_a_b_b_c", SnakeCase("aBbc-s$@a&%_B.B^C"))
cases := map[string]string{
"": "",
"foo-bar": "foo_bar",
"--Foo---Bar-": "foo_bar",
"Foo Bar-": "foo_bar",
"foo_Bar": "foo_bar",
"fooBar": "foo_bar",
"FOOBAR": "foobar",
"FOO_BAR": "foo_bar",
"__FOO_BAR__": "foo_bar",
"$foo@Bar": "foo_bar",
" $#$Foo 22 bar ": "foo_22_bar",
"Foo-#1😄$_%^&*(1bar": "foo_1_1_bar",
}
assert.NotEqual("foo-bar", SnakeCase("foo_Bar"))
for k, v := range cases {
assert.Equal(v, SnakeCase(k))
}
}
func TestUpperSnakeCase(t *testing.T) {
assert := internal.NewAssert(t, "TestUpperSnakeCase")
cases := map[string]string{
"": "",
"foo-bar": "FOO_BAR",
"--Foo---Bar-": "FOO_BAR",
"Foo Bar-": "FOO_BAR",
"foo_Bar": "FOO_BAR",
"fooBar": "FOO_BAR",
"FOOBAR": "FOOBAR",
"FOO_BAR": "FOO_BAR",
"__FOO_BAR__": "FOO_BAR",
"$foo@Bar": "FOO_BAR",
" $#$Foo 22 bar ": "FOO_22_BAR",
"Foo-#1😄$_%^&*(1bar": "FOO_1_1_BAR",
}
for k, v := range cases {
assert.Equal(v, UpperSnakeCase(k))
}
}
func TestUpperFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestLowerFirst")
assert.Equal("Foo", UpperFirst("foo"))
assert.Equal("BAR", UpperFirst("bAR"))
assert.Equal("FOo", UpperFirst("FOo"))
assert.Equal("FOo大", UpperFirst("fOo大"))
cases := map[string]string{
"": "",
"foo": "Foo",
"bAR": "BAR",
"FOo": "FOo",
"fOo大": "FOo大",
}
assert.NotEqual("Bar", UpperFirst("BAR"))
for k, v := range cases {
assert.Equal(v, UpperFirst(k))
}
}
func TestLowerFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestLowerFirst")
assert.Equal("foo", LowerFirst("foo"))
assert.Equal("bAR", LowerFirst("BAR"))
assert.Equal("fOo", LowerFirst("FOo"))
assert.Equal("fOo大", LowerFirst("FOo大"))
cases := map[string]string{
"": "",
"foo": "foo",
"bAR": "bAR",
"FOo": "fOo",
"fOo大": "fOo大",
}
assert.NotEqual("Bar", LowerFirst("BAR"))
for k, v := range cases {
assert.Equal(v, LowerFirst(k))
}
}
func TestPadEnd(t *testing.T) {

View File

@@ -9,6 +9,10 @@ import (
"os"
"os/exec"
"runtime"
"unicode/utf8"
"github.com/duke-git/lancet/validator"
"golang.org/x/text/encoding/simplifiedchinese"
)
// IsWindows check if current os is windows
@@ -50,27 +54,61 @@ func CompareOsEnv(key, comparedEnv string) bool {
return env == comparedEnv
}
// ExecCommand use shell /bin/bash -c to execute command
// ExecCommand execute command, return the stdout and stderr string of command, and error if error occur
// param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1
// in linux, use /bin/bash -c to execute command
// in windows, use powershell.exe to execute command
func ExecCommand(command string) (stdout, stderr string, err error) {
var out bytes.Buffer
var errout bytes.Buffer
var errOut bytes.Buffer
cmd := exec.Command("/bin/bash", "-c", command)
if IsWindows() {
cmd = exec.Command("cmd")
cmd = exec.Command("powershell.exe", command)
}
cmd.Stdout = &out
cmd.Stderr = &errout
cmd.Stderr = &errOut
err = cmd.Run()
if err != nil {
stderr = string(errout.Bytes())
if utf8.Valid(errOut.Bytes()) {
stderr = byteToString(errOut.Bytes(), "UTF8")
} else if validator.IsGBK(errOut.Bytes()) {
stderr = byteToString(errOut.Bytes(), "GBK")
}
return
}
data := out.Bytes()
if utf8.Valid(data) {
stdout = byteToString(data, "UTF8")
} else if validator.IsGBK(data) {
stdout = byteToString(data, "GBK")
}
stdout = string(out.Bytes())
return
}
func byteToString(data []byte, charset string) string {
var result string
switch charset {
case "GBK":
decodeBytes, _ := simplifiedchinese.GBK.NewDecoder().Bytes(data)
result = string(decodeBytes)
case "GB18030":
decodeBytes, _ := simplifiedchinese.GB18030.NewDecoder().Bytes(data)
result = string(decodeBytes)
case "UTF8":
fallthrough
default:
result = string(data)
}
return result
}
// GetOsBits get this system bits 32bit or 64bit
// return bit int (32/64)
func GetOsBits() int {

View File

@@ -11,10 +11,10 @@ func TestOsDetection(t *testing.T) {
assert := internal.NewAssert(t, "TestOsJudgment")
osType, _, _ := ExecCommand("echo $OSTYPE")
if strings.Index(osType, "linux") != -1 {
if strings.Contains(osType, "linux") {
assert.Equal(true, IsLinux())
}
if strings.Index(osType, "darwin") != -1 {
if strings.Contains(osType, "darwin") {
assert.Equal(true, IsMac())
}
}
@@ -44,21 +44,26 @@ func TestOsEnvOperation(t *testing.T) {
func TestExecCommand(t *testing.T) {
assert := internal.NewAssert(t, "TestExecCommand")
out, errout, err := ExecCommand("ls")
t.Log("std out: ", out)
t.Log("std err: ", errout)
// linux or mac
stdout, stderr, err := ExecCommand("ls")
t.Log("std out: ", stdout)
t.Log("std err: ", stderr)
assert.Equal("", stderr)
assert.IsNil(err)
out, errout, err = ExecCommand("abc")
t.Log("std out: ", out)
t.Log("std err: ", errout)
if err != nil {
t.Logf("error: %v\n", err)
// windows
stdout, stderr, err = ExecCommand("dir")
t.Log("std out: ", stdout)
t.Log("std err: ", stderr)
if IsWindows() {
assert.IsNil(err)
}
if !IsWindows() {
assert.IsNotNil(err)
}
// error command
stdout, stderr, err = ExecCommand("abc")
t.Log("std out: ", stdout)
t.Log("std err: ", stderr)
assert.IsNotNil(err)
}
func TestGetOsBits(t *testing.T) {

View File

@@ -15,11 +15,24 @@ import (
"unicode"
)
var isAlphaRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
var (
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
emailMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
base64Matcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
)
// IsAlpha checks if the string contains only letters (a-zA-Z)
func IsAlpha(str string) bool {
return isAlphaRegexMatcher.MatchString(str)
return alphaMatcher.MatchString(str)
}
// IsAllUpper check if the string is all upper case letters A-Z
@@ -62,11 +75,9 @@ func ContainLower(str string) bool {
return false
}
var containLetterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
// ContainLetter check if the string contain at least one letter
func ContainLetter(str string) bool {
return containLetterRegexMatcher.MatchString(str)
return letterRegexMatcher.MatchString(str)
}
// IsJSON checks if the string is valid JSON
@@ -86,11 +97,9 @@ func IsFloatStr(str string) bool {
return e == nil
}
var isIntStrRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
// IsIntStr check if the string can convert to a integer.
func IsIntStr(str string) bool {
return isIntStrRegexMatcher.MatchString(str)
return intStrMatcher.MatchString(str)
}
// IsIp check if the string is a ip address.
@@ -125,8 +134,6 @@ func IsPort(str string) bool {
return false
}
var isUrlRegexMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
// IsUrl check if the string is url.
func IsUrl(str string) bool {
if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
@@ -143,64 +150,48 @@ func IsUrl(str string) bool {
return false
}
return isUrlRegexMatcher.MatchString(str)
return urlMatcher.MatchString(str)
}
var isDnsRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
// IsDns check if the string is dns.
func IsDns(dns string) bool {
return isDnsRegexMatcher.MatchString(dns)
return dnsMatcher.MatchString(dns)
}
var isEmailRegexMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
// IsEmail check if the string is a email address.
func IsEmail(email string) bool {
return isEmailRegexMatcher.MatchString(email)
return emailMatcher.MatchString(email)
}
var isChineseMobileRegexMatcher *regexp.Regexp = regexp.MustCompile("^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$")
// IsChineseMobile check if the string is chinese mobile number.
func IsChineseMobile(mobileNum string) bool {
return isChineseMobileRegexMatcher.MatchString(mobileNum)
return chineseMobileMatcher.MatchString(mobileNum)
}
var isChineseIdNumRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
// IsChineseIdNum check if the string is chinese id number.
func IsChineseIdNum(id string) bool {
return isChineseIdNumRegexMatcher.MatchString(id)
return chineseIdMatcher.MatchString(id)
}
var containChineseRegexMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
// ContainChinese check if the string contain mandarin chinese.
func ContainChinese(s string) bool {
return containChineseRegexMatcher.MatchString(s)
return chineseMatcher.MatchString(s)
}
var isChinesePhoneRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
// IsChinesePhone check if the string is chinese phone number.
// Valid chinese phone is xxx-xxxxxxxx or xxxx-xxxxxxx
func IsChinesePhone(phone string) bool {
return isChinesePhoneRegexMatcher.MatchString(phone)
return chinesePhoneMatcher.MatchString(phone)
}
var isCreditCardRegexMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
// IsCreditCard check if the string is credit card.
func IsCreditCard(creditCart string) bool {
return isCreditCardRegexMatcher.MatchString(creditCart)
return creditCardMatcher.MatchString(creditCart)
}
var isBase64RegexMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
// IsBase64 check if the string is base64 string.
func IsBase64(base64 string) bool {
return isBase64RegexMatcher.MatchString(base64)
return base64Matcher.MatchString(base64)
}
// IsEmptyString check if the string is empty.
@@ -288,3 +279,40 @@ func IsZeroValue(value interface{}) bool {
return reflect.DeepEqual(rv.Interface(), reflect.Zero(rv.Type()).Interface())
}
// IsGBK check if data encoding is gbk
// Note: this function is implemented by whether double bytes fall within the encoding range of gbk,
// while each byte of utf-8 encoding format falls within the encoding range of gbk.
// Therefore, utf8.valid() should be called first to check whether it is not utf-8 encoding,
// and then call IsGBK() to check gbk encoding. like below
/**
data := []byte("你好")
if utf8.Valid(data) {
fmt.Println("data encoding is utf-8")
}else if(IsGBK(data)) {
fmt.Println("data encoding is GBK")
}
fmt.Println("data encoding is unknown")
**/
func IsGBK(data []byte) bool {
i := 0
for i < len(data) {
if data[i] <= 0xff {
i++
continue
} else {
if data[i] >= 0x81 &&
data[i] <= 0xfe &&
data[i+1] >= 0x40 &&
data[i+1] <= 0xfe &&
data[i+1] != 0xf7 {
i += 2
continue
} else {
return false
}
}
}
return true
}

View File

@@ -4,8 +4,10 @@ import (
"fmt"
"testing"
"time"
"unicode/utf8"
"github.com/duke-git/lancet/internal"
"golang.org/x/text/encoding/simplifiedchinese"
)
func TestIsAllUpper(t *testing.T) {
@@ -388,3 +390,13 @@ func TestIsZeroValue(t *testing.T) {
assert.Equal(false, IsZeroValue(value))
}
}
func TestIsGBK(t *testing.T) {
assert := internal.NewAssert(t, "TestIsGBK")
str := "你好"
gbkData, _ := simplifiedchinese.GBK.NewEncoder().Bytes([]byte(str))
assert.Equal(true, IsGBK(gbkData))
assert.Equal(false, utf8.Valid(gbkData))
}