1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

Compare commits

...

10 Commits

Author SHA1 Message Date
dudaodong 2725575d2f doc: add doc for IsGBK' 2022-12-09 19:28:45 +08:00
dudaodong 037d2729ce doc: update doc for ExecCommand 2022-12-09 19:20:15 +08:00
dudaodong 09d98745b0 fix: fix ExecCommand bug in windows 2022-12-09 19:10:55 +08:00
dudaodong af5cfe6da1 feat: add IsGBK validator 2022-12-09 17:36:59 +08:00
Mickls d59259bbe0 feat: A more reasonable IndexOf function (#66) 2022-12-09 11:31:40 +08:00
dudaodong 3189628d54 fix: fix AesCfbDecrypt 2022-12-08 15:07:40 +08:00
dudaodong 62c5e251a5 remove website 2022-12-08 14:55:21 +08:00
dudaodong 6e6444c8c0 refator: clean code 2022-12-06 20:20:36 +08:00
dudaodong dd613e98b2 refator: clean code 2022-12-06 20:00:41 +08:00
dudaodong 2d905ab03e fix: fix word misspelling 2022-12-04 11:25:02 +08:00
19 changed files with 335 additions and 79 deletions
+1 -1
View File
@@ -19,7 +19,7 @@
Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js. Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js.
</p> </p>
English | [简体中文](./README_zh-CN.md) | [Website](https://uvdream.github.io/lancet-docs/en/) English | [简体中文](./README_zh-CN.md)
## Feature ## Feature
+1 -1
View File
@@ -18,7 +18,7 @@
lancet(柳叶刀)是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。 lancet(柳叶刀)是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。
</p> </p>
简体中文 | [English](./README.md) | [文档](https://uvdream.github.io/lancet-docs) 简体中文 | [English](./README.md)
## 特性 ## 特性
+1 -1
View File
@@ -130,7 +130,7 @@ func ToString(value any) string {
newValue, _ := json.Marshal(value) newValue, _ := json.Marshal(value)
return string(newValue) return string(newValue)
// todo: maybe we should't supprt other type convertion // todo: maybe we should't supprt other type conversion
// v := reflect.ValueOf(value) // v := reflect.ValueOf(value)
// log.Panicf("Unsupported data type: %s ", v.String()) // log.Panicf("Unsupported data type: %s ", v.String())
// return "" // return ""
+14 -2
View File
@@ -17,15 +17,19 @@ import (
// AesEcbEncrypt encrypt data with key use AES ECB algorithm // AesEcbEncrypt encrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32 // len(key) should be 16, 24 or 32
func AesEcbEncrypt(data, key []byte) []byte { func AesEcbEncrypt(data, key []byte) []byte {
cipher, _ := aes.NewCipher(generateAesKey(key))
length := (len(data) + aes.BlockSize) / aes.BlockSize length := (len(data) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize) plain := make([]byte, length*aes.BlockSize)
copy(plain, data) copy(plain, data)
pad := byte(len(plain) - len(data)) pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ { for i := len(data); i < len(plain); i++ {
plain[i] = pad plain[i] = pad
} }
encrypted := make([]byte, len(plain)) encrypted := make([]byte, len(plain))
cipher, _ := aes.NewCipher(generateAesKey(key))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() { 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]) cipher.Encrypt(encrypted[bs:be], plain[bs:be])
} }
@@ -108,27 +112,32 @@ func AesCfbEncrypt(data, key []byte) []byte {
encrypted := make([]byte, aes.BlockSize+len(data)) encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize] iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil { if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err) panic(err)
} }
stream := cipher.NewCFBEncrypter(block, iv) stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data) stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted return encrypted
} }
// AesCfbDecrypt decrypt data with key use AES CFB algorithm // AesCfbDecrypt decrypt data with key use AES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32 // len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
func AesCfbDecrypt(encrypted, key []byte) []byte { func AesCfbDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
if len(encrypted) < aes.BlockSize { if len(encrypted) < aes.BlockSize {
panic("encrypted data is too short") panic("encrypted data is too short")
} }
block, _ := aes.NewCipher(key)
iv := encrypted[:aes.BlockSize] iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:] encrypted = encrypted[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv) stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted) stream.XORKeyStream(encrypted, encrypted)
return encrypted return encrypted
} }
@@ -139,6 +148,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
data = pkcs7Padding(data, aes.BlockSize) data = pkcs7Padding(data, aes.BlockSize)
encrypted := make([]byte, aes.BlockSize+len(data)) encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize] iv := encrypted[:aes.BlockSize]
@@ -148,6 +158,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
stream := cipher.NewOFB(block, iv) stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data) stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted return encrypted
} }
@@ -170,5 +181,6 @@ func AesOfbDecrypt(data, key []byte) []byte {
mode.XORKeyStream(decrypted, data) mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted) decrypted = pkcs7UnPadding(decrypted)
return decrypted return decrypted
} }
+3 -1
View File
@@ -15,7 +15,6 @@ import (
// DesEcbEncrypt encrypt data with key use DES ECB algorithm // DesEcbEncrypt encrypt data with key use DES ECB algorithm
// len(key) should be 8 // len(key) should be 8
func DesEcbEncrypt(data, key []byte) []byte { func DesEcbEncrypt(data, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
length := (len(data) + des.BlockSize) / des.BlockSize length := (len(data) + des.BlockSize) / des.BlockSize
plain := make([]byte, length*des.BlockSize) plain := make([]byte, length*des.BlockSize)
copy(plain, data) copy(plain, data)
@@ -26,6 +25,8 @@ func DesEcbEncrypt(data, key []byte) []byte {
} }
encrypted := make([]byte, len(plain)) encrypted := make([]byte, len(plain))
cipher, _ := des.NewCipher(generateDesKey(key))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() { 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]) cipher.Encrypt(encrypted[bs:be], plain[bs:be])
} }
@@ -59,6 +60,7 @@ func DesCbcEncrypt(data, key []byte) []byte {
encrypted := make([]byte, des.BlockSize+len(data)) encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize] iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil { if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err) panic(err)
} }
+19 -5
View File
@@ -211,7 +211,7 @@ func main() {
### <span id="ExecCommand">CompareOsEnv</span> ### <span id="ExecCommand">CompareOsEnv</span>
<p>Use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p> <p>Execute shell 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.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -227,10 +227,24 @@ import (
) )
func main() { func main() {
out, errout, err := system.ExecCommand("ls") // linux or mac
fmt.Println(out) stdout, stderr, err := system.ExecCommand("ls")
fmt.Println(errout) fmt.Println("std out: ", stdout)
fmt.Println(err) fmt.Println("std err: ", stderr)
assert.Equal("", stderr)
// windows
stdout, stderr, err = system.ExecCommand("dir")
fmt.Println("std out: ", stdout)
fmt.Println("std err: ", stderr)
// error command
stdout, stderr, err = system.ExecCommand("abc")
fmt.Println("std out: ", stdout)
fmt.Println("std err: ", stderr)
if err != nil {
fmt.Println(err.Error())
}
} }
``` ```
+19 -5
View File
@@ -212,7 +212,7 @@ func main() {
### <span id="ExecCommand">ExecCommand</span> ### <span id="ExecCommand">ExecCommand</span>
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p> <p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-alinux),dirwindows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令</p>
<b>Signature:</b> <b>Signature:</b>
@@ -228,10 +228,24 @@ import (
) )
func main() { func main() {
out, errout, err := system.ExecCommand("ls") // linux or mac
fmt.Println(out) stdout, stderr, err := system.ExecCommand("ls")
fmt.Println(errout) fmt.Println("std out: ", stdout)
fmt.Println(err) fmt.Println("std err: ", stderr)
assert.Equal("", stderr)
// windows
stdout, stderr, err = system.ExecCommand("dir")
fmt.Println("std out: ", stdout)
fmt.Println("std err: ", stderr)
// error command
stdout, stderr, err = system.ExecCommand("abc")
fmt.Println("std out: ", stdout)
fmt.Println("std err: ", stderr)
if err != nil {
fmt.Println(err.Error())
}
} }
``` ```
+29 -1
View File
@@ -47,6 +47,7 @@ import (
- [IsUrl](#IsUrl) - [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword) - [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue) - [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -821,7 +822,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/v2/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")
}
```
+29
View File
@@ -47,6 +47,7 @@ import (
- [IsUrl](#IsUrl) - [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword) - [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue) - [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -820,3 +821,31 @@ 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/v2/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")
}
```
+2
View File
@@ -1,3 +1,5 @@
module github.com/duke-git/lancet/v2 module github.com/duke-git/lancet/v2
go 1.18 go 1.18
require golang.org/x/text v0.5.0
+2
View File
@@ -0,0 +1,2 @@
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=
+1 -1
View File
@@ -3,7 +3,7 @@
// Package iterator provides a way to iterate over values stored in containers. // Package iterator provides a way to iterate over values stored in containers.
// note: // note:
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go. // 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs. // 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
// 3. It is currently under development, unstable, and will not be completed for some time in the future. // 3. It is currently under development, unstable, and will not be completed for some time in the future.
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it. // So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
+1 -1
View File
@@ -3,7 +3,7 @@
// Package iterator provides a way to iterate over values stored in containers. // Package iterator provides a way to iterate over values stored in containers.
// note: // note:
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go. // 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs. // 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
// 3. It is currently under development, unstable, and will not be completed for some time in the future. // 3. It is currently under development, unstable, and will not be completed for some time in the future.
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it. // So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
+42 -5
View File
@@ -14,6 +14,13 @@ import (
"github.com/duke-git/lancet/v2/lancetconstraints" "github.com/duke-git/lancet/v2/lancetconstraints"
) )
// Create a static variable to store the hash table.
// This variable has the same lifetime as the entire program and can be shared by functions that are called more than once.
var (
memoryHashMap = make(map[string]map[any]int)
memoryHashCounter = make(map[string]int)
)
// Contain check if the target value is in the slice or not // Contain check if the target value is in the slice or not
func Contain[T comparable](slice []T, target T) bool { func Contain[T comparable](slice []T, target T) bool {
for _, item := range slice { for _, item := range slice {
@@ -832,14 +839,44 @@ func Without[T comparable](slice []T, items ...T) []T {
return result return result
} }
// IndexOf returns the index at which the first occurrence of a item is found in a slice or return -1 if the item cannot be found. // IndexOf returns the index at which the first occurrence of an item is found in a slice or return -1 if the item cannot be found.
func IndexOf[T comparable](slice []T, item T) int { func IndexOf[T comparable](arr []T, val T) int {
for i, v := range slice { limit := 10
if v == item { // gets the hash value of the array as the key of the hash table.
return i key := fmt.Sprintf("%p", arr)
// determines whether the hash table is empty. If so, the hash table is created.
if memoryHashMap[key] == nil {
memoryHashMap[key] = make(map[any]int)
// iterate through the array, adding the value and index of each element to the hash table.
for i := len(arr) - 1; i >= 0; i-- {
memoryHashMap[key][arr[i]] = i
} }
} }
// update the hash table counter.
memoryHashCounter[key]++
// use the hash table to find the specified value. If found, the index is returned.
if index, ok := memoryHashMap[key][val]; ok {
// calculate the memory usage of the hash table.
size := len(memoryHashMap)
// If the memory usage of the hash table exceeds the memory limit, the hash table with the lowest counter is cleared.
if size > limit {
var minKey string
var minVal int
for k, v := range memoryHashCounter {
if k == key {
continue
}
if minVal == 0 || v < minVal {
minKey = k
minVal = v
}
}
delete(memoryHashMap, minKey)
delete(memoryHashCounter, minKey)
}
return index
}
return -1 return -1
} }
+32
View File
@@ -1,6 +1,7 @@
package slice package slice
import ( import (
"fmt"
"math" "math"
"testing" "testing"
@@ -669,8 +670,39 @@ func TestIndexOf(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf") assert := internal.NewAssert(t, "TestIndexOf")
arr := []string{"a", "a", "b", "c"} arr := []string{"a", "a", "b", "c"}
key := fmt.Sprintf("%p", arr)
assert.Equal(0, IndexOf(arr, "a")) assert.Equal(0, IndexOf(arr, "a"))
assert.Equal(-1, IndexOf(arr, "d")) assert.Equal(-1, IndexOf(arr, "d"))
assert.Equal(2, memoryHashCounter[key])
arr1 := []int{1, 2, 3, 4, 5}
key1 := fmt.Sprintf("%p", arr1)
assert.Equal(3, IndexOf(arr1, 4))
assert.Equal(-1, IndexOf(arr1, 6))
assert.Equal(2, memoryHashCounter[key1])
arr2 := []float64{1.1, 2.2, 3.3, 4.4, 5.5}
key2 := fmt.Sprintf("%p", arr2)
assert.Equal(2, IndexOf(arr2, 3.3))
assert.Equal(3, IndexOf(arr2, 4.4))
assert.Equal(-1, IndexOf(arr2, 6.6))
assert.Equal(3, memoryHashCounter[key2])
for i := 0; i < 6; i++ {
a := []string{"a", "b", "c"}
IndexOf(a, "a")
IndexOf(a, "b")
}
minArr := []string{"c", "b", "a"}
minKey := fmt.Sprintf("%p", minArr)
assert.Equal(0, IndexOf(minArr, "c"))
arr3 := []string{"q", "w", "e"}
key3 := fmt.Sprintf("%p", arr3)
assert.Equal(1, IndexOf(arr3, "w"))
assert.Equal(-1, IndexOf(arr3, "r"))
assert.Equal(2, memoryHashCounter[key3])
assert.Equal(0, memoryHashCounter[minKey])
} }
func TestLastIndexOf(t *testing.T) { func TestLastIndexOf(t *testing.T) {
+44 -6
View File
@@ -9,6 +9,10 @@ import (
"os" "os"
"os/exec" "os/exec"
"runtime" "runtime"
"unicode/utf8"
"github.com/duke-git/lancet/v2/validator"
"golang.org/x/text/encoding/simplifiedchinese"
) )
// IsWindows check if current os is windows // IsWindows check if current os is windows
@@ -50,27 +54,61 @@ func CompareOsEnv(key, comparedEnv string) bool {
return env == comparedEnv return env == comparedEnv
} }
// ExecCommand use shell /bin/bash -c to execute command // ExecCommand execute command, return the stdout and stderr string of command, and error if error occur
// 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) { func ExecCommand(command string) (stdout, stderr string, err error) {
var out bytes.Buffer var out bytes.Buffer
var errout bytes.Buffer var errOut bytes.Buffer
cmd := exec.Command("/bin/bash", "-c", command) cmd := exec.Command("/bin/bash", "-c", command)
if IsWindows() { if IsWindows() {
cmd = exec.Command("cmd") cmd = exec.Command("powershell.exe", command)
} }
cmd.Stdout = &out cmd.Stdout = &out
cmd.Stderr = &errout cmd.Stderr = &errOut
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
stderr = string(errout.Bytes()) if utf8.Valid(errOut.Bytes()) {
stderr = byteToString(errOut.Bytes(), "UTF8")
} else if validator.IsGBK(errOut.Bytes()) {
stderr = byteToString(errOut.Bytes(), "GBK")
}
return
}
data := out.Bytes()
if utf8.Valid(data) {
stdout = byteToString(data, "UTF8")
} else if validator.IsGBK(data) {
stdout = byteToString(data, "GBK")
} }
stdout = string(out.Bytes())
return return
} }
func byteToString(data []byte, charset string) string {
var result string
switch charset {
case "GBK":
decodeBytes, _ := simplifiedchinese.GBK.NewDecoder().Bytes(data)
result = string(decodeBytes)
case "GB18030":
decodeBytes, _ := simplifiedchinese.GB18030.NewDecoder().Bytes(data)
result = string(decodeBytes)
case "UTF8":
fallthrough
default:
result = string(data)
}
return result
}
// GetOsBits get this system bits 32bit or 64bit // GetOsBits get this system bits 32bit or 64bit
// return bit int (32/64) // return bit int (32/64)
func GetOsBits() int { func GetOsBits() int {
+20 -14
View File
@@ -11,10 +11,10 @@ func TestOsDetection(t *testing.T) {
assert := internal.NewAssert(t, "TestOsJudgment") assert := internal.NewAssert(t, "TestOsJudgment")
osType, _, _ := ExecCommand("echo $OSTYPE") osType, _, _ := ExecCommand("echo $OSTYPE")
if strings.Index(osType, "linux") != -1 { if strings.Contains(osType, "linux") {
assert.Equal(true, IsLinux()) assert.Equal(true, IsLinux())
} }
if strings.Index(osType, "darwin") != -1 { if strings.Contains(osType, "darwin") {
assert.Equal(true, IsMac()) assert.Equal(true, IsMac())
} }
} }
@@ -44,21 +44,27 @@ func TestOsEnvOperation(t *testing.T) {
func TestExecCommand(t *testing.T) { func TestExecCommand(t *testing.T) {
assert := internal.NewAssert(t, "TestExecCommand") assert := internal.NewAssert(t, "TestExecCommand")
out, errout, err := ExecCommand("ls") // linux or mac
t.Log("std out: ", out) stdout, stderr, err := ExecCommand("ls")
t.Log("std err: ", errout) t.Log("std out: ", stdout)
t.Log("std err: ", stderr)
assert.Equal("", stderr)
assert.IsNil(err) assert.IsNil(err)
out, errout, err = ExecCommand("abc") // windows
t.Log("std out: ", out) stdout, stderr, err = ExecCommand("dir")
t.Log("std err: ", errout) t.Log("std out: ", stdout)
if err != nil { t.Log("std err: ", stderr)
t.Logf("error: %v\n", err) assert.IsNil(err)
}
if !IsWindows() { // error command
assert.IsNotNil(err) stdout, stderr, err = ExecCommand("abc")
} t.Log("std out: ", stdout)
t.Log("std err: ", stderr)
// if err != nil {
// t.Log(err.Error())
// }
assert.IsNotNil(err)
} }
func TestGetOsBits(t *testing.T) { func TestGetOsBits(t *testing.T) {
+63 -35
View File
@@ -15,11 +15,24 @@ import (
"unicode" "unicode"
) )
var isAlphaRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`) var (
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
emailMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
base64Matcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
)
// IsAlpha checks if the string contains only letters (a-zA-Z) // IsAlpha checks if the string contains only letters (a-zA-Z)
func IsAlpha(str string) bool { func IsAlpha(str string) bool {
return isAlphaRegexMatcher.MatchString(str) return alphaMatcher.MatchString(str)
} }
// IsAllUpper check if the string is all upper case letters A-Z // IsAllUpper check if the string is all upper case letters A-Z
@@ -62,11 +75,9 @@ func ContainLower(str string) bool {
return false return false
} }
var containLetterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
// ContainLetter check if the string contain at least one letter // ContainLetter check if the string contain at least one letter
func ContainLetter(str string) bool { func ContainLetter(str string) bool {
return containLetterRegexMatcher.MatchString(str) return letterRegexMatcher.MatchString(str)
} }
// IsJSON checks if the string is valid JSON // IsJSON checks if the string is valid JSON
@@ -86,11 +97,9 @@ func IsFloatStr(str string) bool {
return e == nil return e == nil
} }
var isIntStrRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
// IsIntStr check if the string can convert to a integer. // IsIntStr check if the string can convert to a integer.
func IsIntStr(str string) bool { func IsIntStr(str string) bool {
return isIntStrRegexMatcher.MatchString(str) return intStrMatcher.MatchString(str)
} }
// IsIp check if the string is a ip address. // IsIp check if the string is a ip address.
@@ -125,8 +134,6 @@ func IsPort(str string) bool {
return false return false
} }
var isUrlRegexMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
// IsUrl check if the string is url. // IsUrl check if the string is url.
func IsUrl(str string) bool { func IsUrl(str string) bool {
if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") { if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
@@ -143,64 +150,48 @@ func IsUrl(str string) bool {
return false return false
} }
return isUrlRegexMatcher.MatchString(str) return urlMatcher.MatchString(str)
} }
var isDnsRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
// IsDns check if the string is dns. // IsDns check if the string is dns.
func IsDns(dns string) bool { func IsDns(dns string) bool {
return isDnsRegexMatcher.MatchString(dns) return dnsMatcher.MatchString(dns)
} }
var isEmailRegexMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
// IsEmail check if the string is a email address. // IsEmail check if the string is a email address.
func IsEmail(email string) bool { func IsEmail(email string) bool {
return isEmailRegexMatcher.MatchString(email) return emailMatcher.MatchString(email)
} }
var isChineseMobileRegexMatcher *regexp.Regexp = regexp.MustCompile("^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$")
// IsChineseMobile check if the string is chinese mobile number. // IsChineseMobile check if the string is chinese mobile number.
func IsChineseMobile(mobileNum string) bool { func IsChineseMobile(mobileNum string) bool {
return isChineseMobileRegexMatcher.MatchString(mobileNum) return chineseMobileMatcher.MatchString(mobileNum)
} }
var isChineseIdNumRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
// IsChineseIdNum check if the string is chinese id number. // IsChineseIdNum check if the string is chinese id number.
func IsChineseIdNum(id string) bool { func IsChineseIdNum(id string) bool {
return isChineseIdNumRegexMatcher.MatchString(id) return chineseIdMatcher.MatchString(id)
} }
var containChineseRegexMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
// ContainChinese check if the string contain mandarin chinese. // ContainChinese check if the string contain mandarin chinese.
func ContainChinese(s string) bool { func ContainChinese(s string) bool {
return containChineseRegexMatcher.MatchString(s) return chineseMatcher.MatchString(s)
} }
var isChinesePhoneRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`)
// IsChinesePhone check if the string is chinese phone number. // IsChinesePhone check if the string is chinese phone number.
// Valid chinese phone is xxx-xxxxxxxx or xxxx-xxxxxxx // Valid chinese phone is xxx-xxxxxxxx or xxxx-xxxxxxx
func IsChinesePhone(phone string) bool { func IsChinesePhone(phone string) bool {
return isChinesePhoneRegexMatcher.MatchString(phone) return chinesePhoneMatcher.MatchString(phone)
} }
var isCreditCardRegexMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
// IsCreditCard check if the string is credit card. // IsCreditCard check if the string is credit card.
func IsCreditCard(creditCart string) bool { func IsCreditCard(creditCart string) bool {
return isCreditCardRegexMatcher.MatchString(creditCart) return creditCardMatcher.MatchString(creditCart)
} }
var isBase64RegexMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
// IsBase64 check if the string is base64 string. // IsBase64 check if the string is base64 string.
func IsBase64(base64 string) bool { func IsBase64(base64 string) bool {
return isBase64RegexMatcher.MatchString(base64) return base64Matcher.MatchString(base64)
} }
// IsEmptyString check if the string is empty. // IsEmptyString check if the string is empty.
@@ -283,3 +274,40 @@ func IsZeroValue(value any) bool {
return reflect.DeepEqual(rv.Interface(), reflect.Zero(rv.Type()).Interface()) 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
}
+12
View File
@@ -4,8 +4,10 @@ import (
"fmt" "fmt"
"testing" "testing"
"time" "time"
"unicode/utf8"
"github.com/duke-git/lancet/v2/internal" "github.com/duke-git/lancet/v2/internal"
"golang.org/x/text/encoding/simplifiedchinese"
) )
func TestIsAllUpper(t *testing.T) { func TestIsAllUpper(t *testing.T) {
@@ -388,3 +390,13 @@ func TestIsZeroValue(t *testing.T) {
assert.Equal(false, IsZeroValue(value)) 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))
}