- 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)
258 lines
5.9 KiB
Go
258 lines
5.9 KiB
Go
// 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()
|
||
}
|