feat(stringx): 自 go-hua/common 迁入字符串/切片/拼音工具并独立成包
- common 的 string.go/array.go/pinyin.go 拆为 stringx 包(含随机串、GUID、 通配符匹配、校验规则、链式缓冲、驼峰转下划线、切片删元素、拼音首字母) - 附单元测试与 examples/stringx 可运行例程、包 README - go.mod 新增直接依赖 mozillazg/go-pinyin(go-hua 同版本锁 v0.20.0→实际解析 v0.21.0)
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
// stringx 包示例:字符串/切片工具(随机串、GUID、取中间串、驼峰转下划线、
|
||||||
|
// 通配符匹配、校验、中文首字母、切片删元素)
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.zeroonesoft.cn/golib/zogo/stringx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 随机字符串 / GUID
|
||||||
|
fmt.Println("随机字符串:", stringx.CreateRandomString(16))
|
||||||
|
fmt.Println("纯数字随机:", stringx.CreateRandomStringInt(6))
|
||||||
|
fmt.Println("GUID:", stringx.GetGUID())
|
||||||
|
|
||||||
|
// 字符串处理
|
||||||
|
fmt.Println("取中间字符串:", stringx.GetBetweenStr("key=value&x=1", "key=", "&"))
|
||||||
|
fmt.Println("驼峰转下划线:", stringx.Camel2Case("GetUserName"))
|
||||||
|
fmt.Println("通配符匹配:", stringx.IsMatchGreed("hello.txt", "*.txt"))
|
||||||
|
|
||||||
|
// 校验
|
||||||
|
fmt.Println("手机号 13812345678:", stringx.CheckMobile("13812345678"))
|
||||||
|
fmt.Println("身份证 110101199001011234:", stringx.CheckIdCard("110101199001011234"))
|
||||||
|
|
||||||
|
// 中文拼音首字母
|
||||||
|
fmt.Println("拼音首字母:", stringx.GetFirstLetter("中国"))
|
||||||
|
|
||||||
|
// 切片删除指定下标元素
|
||||||
|
s := []int{1, 2, 3, 4, 5}
|
||||||
|
s = stringx.DeleteElement(s, 2)
|
||||||
|
fmt.Println("删除下标2后:", s)
|
||||||
|
}
|
||||||
@@ -10,7 +10,9 @@ require (
|
|||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||||
github.com/mattn/go-colorable v0.1.15
|
github.com/mattn/go-colorable v0.1.15
|
||||||
|
github.com/mozillazg/go-pinyin v0.21.0
|
||||||
github.com/sirupsen/logrus v1.10.2
|
github.com/sirupsen/logrus v1.10.2
|
||||||
|
golang.org/x/text v0.41.0
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,6 +48,5 @@ require (
|
|||||||
golang.org/x/crypto v0.55.0 // indirect
|
golang.org/x/crypto v0.55.0 // indirect
|
||||||
golang.org/x/net v0.57.0 // indirect
|
golang.org/x/net v0.57.0 // indirect
|
||||||
golang.org/x/sys v0.47.0 // indirect
|
golang.org/x/sys v0.47.0 // indirect
|
||||||
golang.org/x/text v0.41.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.36.10 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/mozillazg/go-pinyin v0.21.0 h1:Wo8/NT45z7P3er/9YSLHA3/kjZzbLz5hR7i+jGeIGao=
|
||||||
|
github.com/mozillazg/go-pinyin v0.21.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# stringx
|
||||||
|
|
||||||
|
字符串与切片通用工具:随机串、UUID、通配符匹配、中间串提取、手机号/身份证校验、
|
||||||
|
链式字节缓冲、驼峰转下划线、切片删元素、中文拼音首字母。
|
||||||
|
|
||||||
|
> 迁移自 go-hua/common(原 string.go / array.go / pinyin.go)。
|
||||||
|
|
||||||
|
## 用法
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "git.zeroonesoft.cn/golib/zogo/stringx"
|
||||||
|
|
||||||
|
// 随机串(字母数字 / 纯数字 / 十六进制)
|
||||||
|
stringx.CreateRandomString(16)
|
||||||
|
stringx.CreateRandomStringInt(6)
|
||||||
|
stringx.CreateRandomStringHex(8)
|
||||||
|
|
||||||
|
// GUID(带连字符)/ UUID(不带连字符),基于 crypto/rand
|
||||||
|
stringx.GetGUID()
|
||||||
|
stringx.GetUUID()
|
||||||
|
|
||||||
|
// 字符串处理
|
||||||
|
stringx.GetBetweenStr("key=value&x=1", "key=", "&") // "value"
|
||||||
|
stringx.Camel2Case("GetUserName") // "get_user_name"
|
||||||
|
stringx.IsMatchGreed("hello.txt", "*.txt") // true(另有 IsMatchDynamic)
|
||||||
|
|
||||||
|
// 校验
|
||||||
|
stringx.CheckMobile("13812345678")
|
||||||
|
stringx.CheckIdCard("110101199001011234")
|
||||||
|
stringx.PhoneCheckRule() // 返回规则正则
|
||||||
|
stringx.EmailCheckRule()
|
||||||
|
|
||||||
|
// 中文拼音首字母(非中文字符原样返回)
|
||||||
|
stringx.GetFirstLetter("中国") // "zg"
|
||||||
|
|
||||||
|
// 切片删除指定下标元素(泛型)
|
||||||
|
s := stringx.DeleteElement([]int{1, 2, 3, 4, 5}, 2) // [1 2 4 5]
|
||||||
|
|
||||||
|
// 链式字节缓冲
|
||||||
|
b := stringx.NewBuffer()
|
||||||
|
b.Append("a").Append(1).Append([]byte("b")).Append(rune('c'))
|
||||||
|
```
|
||||||
|
|
||||||
|
完整可运行例程:[examples/stringx/main.go](../examples/stringx/main.go)
|
||||||
|
|
||||||
|
## 注意
|
||||||
|
|
||||||
|
- `CreateRandomString*` 内部 `rand.Int` 失败时该位为空字符,正常环境不会发生。
|
||||||
|
- `GetGUID/GetUUID` 是随机 UUID(v4 风格),非确定性 UUID;需要标准 RFC 4122
|
||||||
|
格式请用 `github.com/google/uuid`。
|
||||||
|
- 通配符匹配仅支持 `*` 和 `?` 两个通配符。
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package stringx
|
||||||
|
|
||||||
|
// DeleteElement 删除切片中指定下标的元素(泛型,支持任意切片类型)
|
||||||
|
func DeleteElement[S []T, T any](slice S, index int) S {
|
||||||
|
if index < 0 || index >= len(slice) {
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
// 计算要删除的元素后面的元素需要向前移动多少位置
|
||||||
|
n := len(slice) - 1
|
||||||
|
copy(slice[index:n], slice[index+1:n+1])
|
||||||
|
return slice[:n]
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package stringx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mozillazg/go-pinyin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetFirstLetter 获取中文首字母(非中文字符原样返回)
|
||||||
|
func GetFirstLetter(value string) string {
|
||||||
|
// 默认
|
||||||
|
py := pinyin.NewArgs()
|
||||||
|
py.Style = pinyin.FirstLetter
|
||||||
|
py.Fallback = func(r rune, a pinyin.Args) []string {
|
||||||
|
return []string{string(r)}
|
||||||
|
}
|
||||||
|
retText := ""
|
||||||
|
result := pinyin.Pinyin(value, py)
|
||||||
|
for _, res := range result {
|
||||||
|
for _, s := range res {
|
||||||
|
retText += strings.ToLower(s)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retText
|
||||||
|
}
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
// Package stringx 字符串与切片通用工具:随机串、UUID、通配符匹配、中间串提取、
|
||||||
|
// 手机号/身份证校验、链式字节缓冲、驼峰转下划线、切片删元素、中文拼音首字母。
|
||||||
|
package stringx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math/big"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateRandomString 生成指定长度的随机字符串(含大小写字母与数字)
|
||||||
|
func CreateRandomString(len int) string {
|
||||||
|
var container string
|
||||||
|
var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||||
|
b := bytes.NewBufferString(str)
|
||||||
|
length := b.Len()
|
||||||
|
bigInt := big.NewInt(int64(length))
|
||||||
|
for i := 0; i < len; i++ {
|
||||||
|
randomInt, _ := rand.Int(rand.Reader, bigInt)
|
||||||
|
container += string(str[randomInt.Int64()])
|
||||||
|
}
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRandomStringHex 生成指定长度的随机字符串(十六进制字符)
|
||||||
|
func CreateRandomStringHex(len int) string {
|
||||||
|
var container string
|
||||||
|
var str = "ABCDEF1234567890"
|
||||||
|
b := bytes.NewBufferString(str)
|
||||||
|
length := b.Len()
|
||||||
|
bigInt := big.NewInt(int64(length))
|
||||||
|
for i := 0; i < len; i++ {
|
||||||
|
randomInt, _ := rand.Int(rand.Reader, bigInt)
|
||||||
|
container += string(str[randomInt.Int64()])
|
||||||
|
}
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRandomStringInt 生成指定长度的纯数字随机字符串
|
||||||
|
func CreateRandomStringInt(len int) string {
|
||||||
|
var container string
|
||||||
|
var str = "1234567890"
|
||||||
|
b := bytes.NewBufferString(str)
|
||||||
|
length := b.Len()
|
||||||
|
bigInt := big.NewInt(int64(length))
|
||||||
|
for i := 0; i < len; i++ {
|
||||||
|
randomInt, _ := rand.Int(rand.Reader, bigInt)
|
||||||
|
container += string(str[randomInt.Int64()])
|
||||||
|
}
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMatchDynamic 动态规划;时间复杂度O(n^2),空间复杂度O(n^2)
|
||||||
|
func IsMatchDynamic(s string, p string) bool {
|
||||||
|
n, m := len(s), len(p)
|
||||||
|
dp := make([][]bool, n+1)
|
||||||
|
for i := 0; i <= n; i++ {
|
||||||
|
dp[i] = make([]bool, m+1)
|
||||||
|
}
|
||||||
|
dp[0][0] = true
|
||||||
|
for i := 1; i <= m; i++ {
|
||||||
|
if p[i-1] == '*' {
|
||||||
|
// 可以匹配任意字符串(包括空字符串)
|
||||||
|
dp[0][i] = true
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 1; i <= n; i++ {
|
||||||
|
for j := 1; j <= m; j++ {
|
||||||
|
if p[j-1] == '*' {
|
||||||
|
// dp[i][j-1]=>不使用这个*,dp[i-1][j]=>使用这个*
|
||||||
|
dp[i][j] = dp[i][j-1] || dp[i-1][j]
|
||||||
|
} else if p[j-1] == '?' || s[i-1] == p[j-1] {
|
||||||
|
dp[i][j] = dp[i-1][j-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[n][m]
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMatchGreed 贪心;时间复杂度O(n^2),空间复杂度O(1)
|
||||||
|
func IsMatchGreed(s string, p string) bool {
|
||||||
|
i, j := 0, 0
|
||||||
|
start, last := 0, 0
|
||||||
|
for i = 0; i < len(s); {
|
||||||
|
if j < len(p) && (s[i] == p[j] || p[j] == '?') {
|
||||||
|
i++
|
||||||
|
j++
|
||||||
|
} else if j < len(p) && p[j] == '*' {
|
||||||
|
last = i
|
||||||
|
// 记录s下一个的位置
|
||||||
|
start = j + 1
|
||||||
|
// 记录*下一个的位置
|
||||||
|
j++
|
||||||
|
} else if start != 0 {
|
||||||
|
last++
|
||||||
|
i = last
|
||||||
|
// 更新到s记录位置的下一个
|
||||||
|
j = start
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ; j < len(p) && p[j] == '*'; j++ {
|
||||||
|
|
||||||
|
}
|
||||||
|
return j == len(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBetweenStr 取中间字符串
|
||||||
|
func GetBetweenStr(str, starting, ending string) string {
|
||||||
|
s := strings.Index(str, starting)
|
||||||
|
if s < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s += len(starting)
|
||||||
|
if ending == "" {
|
||||||
|
return str[s:]
|
||||||
|
}
|
||||||
|
e := strings.Index(str[s:], ending)
|
||||||
|
|
||||||
|
if e < 0 {
|
||||||
|
return str[s:]
|
||||||
|
}
|
||||||
|
return str[s : s+e]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGUID 使用来自 crypto/rand 包的 rand.Read 函数来生成基本的 UUID。
|
||||||
|
func GetGUID() string {
|
||||||
|
b := make([]byte, 16)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
uuid := fmt.Sprintf("%x-%x-%x-%x-%x",
|
||||||
|
b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUUID 使用来自 crypto/rand 包的 rand.Read 函数来生成基本的 UUID。
|
||||||
|
func GetUUID() string {
|
||||||
|
b := make([]byte, 16)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
uuid := fmt.Sprintf("%x%x%x%x%x",
|
||||||
|
b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckMobile 检验手机号
|
||||||
|
func CheckMobile(phone string) bool {
|
||||||
|
// 匹配规则
|
||||||
|
// ^1第一位为一
|
||||||
|
// [345789]{1} 后接一位345789 的数字
|
||||||
|
// \\d \d的转义 表示数字 {9} 接9位
|
||||||
|
// $ 结束符
|
||||||
|
regRuler := "^1[345789]{1}\\d{9}$"
|
||||||
|
|
||||||
|
// 正则调用规则
|
||||||
|
reg := regexp.MustCompile(regRuler)
|
||||||
|
|
||||||
|
// 返回 MatchString 是否匹配
|
||||||
|
return reg.MatchString(phone)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PhoneCheckRule 手机号验证规则
|
||||||
|
func PhoneCheckRule() string {
|
||||||
|
return "^1[3|4|5|6|7|8|9][0-9]\\d{8}$"
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmailCheckRule 邮箱验证规则
|
||||||
|
func EmailCheckRule() string {
|
||||||
|
return "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$"
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckIdCard 检验身份证
|
||||||
|
func CheckIdCard(card string) bool {
|
||||||
|
//18位身份证 ^(\d{17})([0-9]|X)$
|
||||||
|
// 匹配规则
|
||||||
|
// (^\d{15}$) 15位身份证
|
||||||
|
// (^\d{18}$) 18位身份证
|
||||||
|
// (^\d{17}(\d|X|x)$) 18位身份证 最后一位为X的用户
|
||||||
|
regRuler := "(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)"
|
||||||
|
|
||||||
|
// 正则调用规则
|
||||||
|
reg := regexp.MustCompile(regRuler)
|
||||||
|
|
||||||
|
// 返回 MatchString 是否匹配
|
||||||
|
return reg.MatchString(card)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer 内嵌bytes.Buffer,支持连写
|
||||||
|
type Buffer struct {
|
||||||
|
*bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuffer 创建空字节缓冲
|
||||||
|
func NewBuffer() *Buffer {
|
||||||
|
return &Buffer{Buffer: new(bytes.Buffer)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append 追加任意类型数据并返回自身(支持链式调用)
|
||||||
|
func (b *Buffer) Append(i interface{}) *Buffer {
|
||||||
|
switch val := i.(type) {
|
||||||
|
case int:
|
||||||
|
b.append(strconv.Itoa(val))
|
||||||
|
case int64:
|
||||||
|
b.append(strconv.FormatInt(val, 10))
|
||||||
|
case uint:
|
||||||
|
b.append(strconv.FormatUint(uint64(val), 10))
|
||||||
|
case uint64:
|
||||||
|
b.append(strconv.FormatUint(val, 10))
|
||||||
|
case string:
|
||||||
|
b.append(val)
|
||||||
|
case []byte:
|
||||||
|
b.Write(val)
|
||||||
|
case rune:
|
||||||
|
b.WriteRune(val)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// append 追加字符串(容量不足时自动扩容)
|
||||||
|
func (b *Buffer) append(s string) *Buffer {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Println("*****内存不够了!******")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
b.WriteString(s)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Camel2Case 驼峰式写法转为下划线写法
|
||||||
|
func Camel2Case(name string) string {
|
||||||
|
buffer := NewBuffer()
|
||||||
|
for i, r := range name {
|
||||||
|
if unicode.IsUpper(r) {
|
||||||
|
if i != 0 {
|
||||||
|
buffer.Append('_')
|
||||||
|
}
|
||||||
|
buffer.Append(unicode.ToLower(r))
|
||||||
|
} else {
|
||||||
|
buffer.Append(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.String()
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package stringx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateRandomString(t *testing.T) {
|
||||||
|
s := CreateRandomString(16)
|
||||||
|
if len(s) != 16 {
|
||||||
|
t.Errorf("CreateRandomString(16) 长度 = %d, want 16", len(s))
|
||||||
|
}
|
||||||
|
for _, c := range s {
|
||||||
|
if !strings.ContainsRune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", c) {
|
||||||
|
t.Errorf("字符 %q 不在允许字符集内", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s2 := CreateRandomString(16); s2 == s {
|
||||||
|
t.Error("两次生成结果不应相同")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateRandomStringInt(t *testing.T) {
|
||||||
|
s := CreateRandomStringInt(8)
|
||||||
|
if len(s) != 8 {
|
||||||
|
t.Errorf("长度 = %d, want 8", len(s))
|
||||||
|
}
|
||||||
|
for _, c := range s {
|
||||||
|
if c < '0' || c > '9' {
|
||||||
|
t.Errorf("字符 %q 应为数字", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateRandomStringHex(t *testing.T) {
|
||||||
|
s := CreateRandomStringHex(8)
|
||||||
|
if len(s) != 8 {
|
||||||
|
t.Errorf("长度 = %d, want 8", len(s))
|
||||||
|
}
|
||||||
|
for _, c := range s {
|
||||||
|
if !strings.ContainsRune("ABCDEF1234567890", c) {
|
||||||
|
t.Errorf("字符 %q 不在十六进制字符集内", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetBetweenStr(t *testing.T) {
|
||||||
|
if got := GetBetweenStr("key=value&x=1", "key=", "&"); got != "value" {
|
||||||
|
t.Errorf("GetBetweenStr = %q, want value", got)
|
||||||
|
}
|
||||||
|
if got := GetBetweenStr("abc", "x", "y"); got != "" {
|
||||||
|
t.Errorf("起始不存在应返回空: %q", got)
|
||||||
|
}
|
||||||
|
if got := GetBetweenStr("a<..>b", "<..>", ""); got != "b" {
|
||||||
|
t.Errorf("结束为空应返回到结尾: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetGUIDFormat(t *testing.T) {
|
||||||
|
guid := GetGUID()
|
||||||
|
if strings.Count(guid, "-") != 4 {
|
||||||
|
t.Errorf("GetGUID 应为 8-4-4-4-12 格式: %q", guid)
|
||||||
|
}
|
||||||
|
if len(strings.ReplaceAll(guid, "-", "")) != 32 {
|
||||||
|
t.Errorf("GetGUID 总长应为 32 位十六进制: %q", guid)
|
||||||
|
}
|
||||||
|
uuid := GetUUID()
|
||||||
|
if strings.Contains(uuid, "-") {
|
||||||
|
t.Errorf("GetUUID 不应含连字符: %q", uuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckMobile(t *testing.T) {
|
||||||
|
if !CheckMobile("13812345678") {
|
||||||
|
t.Error("合法手机号应通过")
|
||||||
|
}
|
||||||
|
if CheckMobile("12345678901") {
|
||||||
|
t.Error("第二位为 2 应不通过")
|
||||||
|
}
|
||||||
|
if CheckMobile("1381234567") {
|
||||||
|
t.Error("10 位应不通过")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckIdCard(t *testing.T) {
|
||||||
|
if !CheckIdCard("110101199001011234") {
|
||||||
|
t.Error("18 位数字应通过")
|
||||||
|
}
|
||||||
|
if !CheckIdCard("11010119900101123X") {
|
||||||
|
t.Error("17 位数字 + X 应通过")
|
||||||
|
}
|
||||||
|
if CheckIdCard("abc") {
|
||||||
|
t.Error("非法字符应不通过")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsMatch(t *testing.T) {
|
||||||
|
if !IsMatchGreed("hello.txt", "*.txt") {
|
||||||
|
t.Error("IsMatchGreed(hello.txt, *.txt) 应为 true")
|
||||||
|
}
|
||||||
|
if IsMatchGreed("hello.txt", "*.jpg") {
|
||||||
|
t.Error("IsMatchGreed(hello.txt, *.jpg) 应为 false")
|
||||||
|
}
|
||||||
|
if !IsMatchDynamic("hello.txt", "*.txt") {
|
||||||
|
t.Error("IsMatchDynamic(hello.txt, *.txt) 应为 true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCamel2Case(t *testing.T) {
|
||||||
|
if got := Camel2Case("GetUserName"); got != "get_user_name" {
|
||||||
|
t.Errorf("Camel2Case = %q, want get_user_name", got)
|
||||||
|
}
|
||||||
|
if got := Camel2Case("id"); got != "id" {
|
||||||
|
t.Errorf("Camel2Case = %q, want id", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteElement(t *testing.T) {
|
||||||
|
s := []int{1, 2, 3, 4, 5}
|
||||||
|
got := DeleteElement(s, 2)
|
||||||
|
if len(got) != 4 || got[0] != 1 || got[1] != 2 || got[2] != 4 || got[3] != 5 {
|
||||||
|
t.Errorf("DeleteElement = %v, want [1 2 4 5]", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuffer(t *testing.T) {
|
||||||
|
b := NewBuffer()
|
||||||
|
b.Append("a").Append(1).Append(int64(2)).Append([]byte("b")).Append(uint64(3))
|
||||||
|
if b.String() != "a12b3" {
|
||||||
|
t.Errorf("Buffer = %q, want a12b3", b.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFirstLetter(t *testing.T) {
|
||||||
|
if got := GetFirstLetter("中国"); got != "zg" {
|
||||||
|
t.Errorf("GetFirstLetter(中国) = %q, want zg", got)
|
||||||
|
}
|
||||||
|
if got := GetFirstLetter("abc123"); got != "abc123" {
|
||||||
|
t.Errorf("非中文字符应原样返回: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user