package utils import ( "crypto/md5" "fmt" "path/filepath" "regexp" "strings" "time" "unicode" "golang.org/x/text/runes" "golang.org/x/text/transform" "golang.org/x/text/unicode/norm" ) // Contains 检查字符串切片是否包含指定字符串 func Contains(slice []string, item string) bool { for _, s := range slice { if s == item { return true } } return false } // ContainsUint 检查 uint 切片是否包含指定值 func ContainsUint(slice []uint, item uint) bool { for _, s := range slice { if s == item { return true } } return false } // GenerateUniqueFilename 生成唯一文件名 func GenerateUniqueFilename(originalFilename string) string { ext := filepath.Ext(originalFilename) name := strings.TrimSuffix(originalFilename, ext) // 生成时间戳和哈希 timestamp := time.Now().Unix() hash := md5.Sum([]byte(fmt.Sprintf("%s%d", name, timestamp))) return fmt.Sprintf("%d_%x%s", timestamp, hash[:8], ext) } // GenerateSlug 生成 URL 友好的 slug func GenerateSlug(text string) string { // 转换为小写 slug := strings.ToLower(text) // 移除重音符号 t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) slug, _, _ = transform.String(t, slug) // 只保留字母、数字、连字符和下划线 reg := regexp.MustCompile(`[^a-z0-9\-_\s]`) slug = reg.ReplaceAllString(slug, "") // 将空格替换为连字符 slug = regexp.MustCompile(`\s+`).ReplaceAllString(slug, "-") // 移除多余的连字符 slug = regexp.MustCompile(`-+`).ReplaceAllString(slug, "-") // 移除开头和结尾的连字符 slug = strings.Trim(slug, "-") return slug } // ValidateEmail 验证邮箱格式 func ValidateEmail(email string) bool { emailRegex := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`) return emailRegex.MatchString(strings.ToLower(email)) } // ValidatePassword 验证密码强度 func ValidatePassword(password string) bool { if len(password) < 8 { return false } hasLower := regexp.MustCompile(`[a-z]`).MatchString(password) hasUpper := regexp.MustCompile(`[A-Z]`).MatchString(password) hasDigit := regexp.MustCompile(`\d`).MatchString(password) return hasLower && hasUpper && hasDigit } // Paginate 计算分页参数 func Paginate(page, limit int) (offset int) { if page <= 0 { page = 1 } if limit <= 0 { limit = 20 } if limit > 100 { limit = 100 } offset = (page - 1) * limit return offset } // CalculatePages 计算总页数 func CalculatePages(total int64, limit int) int { if limit <= 0 { return 0 } return int((total + int64(limit) - 1) / int64(limit)) } // TruncateString 截断字符串 func TruncateString(s string, maxLength int) string { if len(s) <= maxLength { return s } return s[:maxLength] + "..." } // FormatFileSize 格式化文件大小 func FormatFileSize(bytes int64) string { const unit = 1024 if bytes < unit { return fmt.Sprintf("%d B", bytes) } div, exp := int64(unit), 0 for n := bytes / unit; n >= unit; n /= unit { div *= unit exp++ } sizes := []string{"KB", "MB", "GB", "TB", "PB"} return fmt.Sprintf("%.1f %s", float64(bytes)/float64(div), sizes[exp]) } // ParseSortOrder 解析排序方向 func ParseSortOrder(order string) string { order = strings.ToLower(strings.TrimSpace(order)) if order == "asc" || order == "desc" { return order } return "desc" // 默认降序 } // SanitizeSearchQuery 清理搜索查询 func SanitizeSearchQuery(query string) string { // 移除特殊字符,只保留字母、数字、空格和常用标点 reg := regexp.MustCompile(`[^\w\s\-\.\_\@]`) query = reg.ReplaceAllString(query, "") // 移除多余的空格 query = regexp.MustCompile(`\s+`).ReplaceAllString(query, " ") return strings.TrimSpace(query) } // GenerateRandomString 生成随机字符串 func GenerateRandomString(length int) string { const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // 使用当前时间作为种子 timestamp := time.Now().UnixNano() result := make([]byte, length) for i := range result { result[i] = charset[(timestamp+int64(i))%int64(len(charset))] } return string(result) } // IsValidImageExtension 检查是否为有效的图片扩展名 func IsValidImageExtension(filename string) bool { ext := strings.ToLower(filepath.Ext(filename)) validExts := []string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".tiff"} return Contains(validExts, ext) } // GetImageMimeType 根据文件扩展名获取 MIME 类型 func GetImageMimeType(filename string) string { ext := strings.ToLower(filepath.Ext(filename)) mimeTypes := map[string]string{ ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".gif": "image/gif", ".webp": "image/webp", ".bmp": "image/bmp", ".tiff": "image/tiff", } if mimeType, exists := mimeTypes[ext]; exists { return mimeType } return "application/octet-stream" } // RemoveEmptyStrings 移除字符串切片中的空字符串 func RemoveEmptyStrings(slice []string) []string { var result []string for _, s := range slice { if strings.TrimSpace(s) != "" { result = append(result, strings.TrimSpace(s)) } } return result } // UniqueStrings 去重字符串切片 func UniqueStrings(slice []string) []string { keys := make(map[string]bool) var result []string for _, item := range slice { if !keys[item] { keys[item] = true result = append(result, item) } } return result } // UniqueUints 去重 uint 切片 func UniqueUints(slice []uint) []uint { keys := make(map[uint]bool) var result []uint for _, item := range slice { if !keys[item] { keys[item] = true result = append(result, item) } } return result }