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:
2026-09-20 12:20:28 +08:00
parent 1d0120d2c2
commit d13de8f3fa
8 changed files with 524 additions and 1 deletions
+257
View File
@@ -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()
}