base-golang/tool/helper.go
2024-08-09 15:39:57 +08:00

330 lines
7.4 KiB
Go

package tool
import (
"bufio"
"bytes"
"errors"
"fmt"
"github.com/spf13/cast"
"io"
"math"
"math/rand"
"net"
"net/http"
"net/url"
"os"
"regexp"
"strconv"
"strings"
"time"
"unicode"
)
// GetOrderNumber 获取订单号
func GetOrderNumber() string {
parse, _ := time.Parse(time.DateTime, "2021-04-27 00:00:00")
hours := time.Now().Sub(parse).Hours()
day := math.Floor(hours / 24)
prefix := fmt.Sprintf("%05d", int64(day))
format := time.Now().Format("") + "%0" + strconv.Itoa(10) + "d"
n := math.Pow10(10)
return prefix + fmt.Sprintf(format, rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(int64(n)))
}
// ByteFmt 格式化显示文件大小
func ByteFmt(size int64) string {
var unitArr = []string{"B", "KB", "MB", "GB", "TB", "EB"}
if size <= 0 {
return "unknown"
}
fs := float64(size)
p := int(math.Log(fs) / math.Log(1024))
val := fs / math.Pow(1024, float64(p))
_, frac := math.Modf(val)
if frac > 0 {
return fmt.Sprintf("%.1f%s", math.Floor(val*10)/10, unitArr[p])
} else {
return fmt.Sprintf("%d%s", cast.ToInt(val), unitArr[p])
}
}
// UniqueArray 切片唯一值
func UniqueArray[T comparable](array []T) []T {
result := make([]T, 0, len(array))
temp := map[T]struct{}{}
for _, item := range array {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}
// InArray 是否在切片
func InArray[T comparable](item T, array []T) bool {
for _, s := range array {
if item == s {
return true
}
}
return false
}
// ChunkArray 分割切片
func ChunkArray[T comparable](array []T, size int) (ss [][]T) {
if size <= 0 || len(array) <= size {
return [][]T{array}
}
mod := len(array) % size
k := len(array) / size
var end int
if mod == 0 {
end = k
} else {
end = k + 1
}
for i := 0; i < end; i++ {
if i != k {
ss = append(ss, array[i*size:(i+1)*size])
} else {
ss = append(ss, array[i*size:])
}
}
return
}
// IsChinese 判断字符串是否包含中文
func IsChinese(str string) bool {
var count int
for _, v := range str {
if unicode.Is(unicode.Han, v) {
count++
break
}
}
return count > 0
}
// RandInt 随机数
func RandInt(max int) int {
if max <= 0 {
return 0
}
return rand.Intn(max)
}
// FindIPv4 字符串中查找IP4
func FindIPv4(input string) string {
partIp := "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
must := partIp + "\\." + partIp + "\\." + partIp + "\\." + partIp
matchMe := regexp.MustCompile(must)
return matchMe.FindString(input)
}
// RandString 随机字符串
func RandString(n int) string {
var letterRunes = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[RandInt(len(letterRunes))]
}
return string(b)
}
// IP4ToInt ip4地址转Int类型
func IP4ToInt(ip net.IP) int {
ipSplit := strings.Split(ip.To4().String(), ".")
var ipInt = 0
var pos uint = 24
for _, ipSeg := range ipSplit {
tempInt, _ := strconv.Atoi(ipSeg)
tempInt = tempInt << pos
ipInt = ipInt | tempInt
pos -= 8
}
return ipInt
}
// IP4IntToString 反序列化Int为IP4地址
func IP4IntToString(ipInt int) string {
ipSplit := make([]string, 4)
var length = len(ipSplit)
buffer := bytes.NewBufferString("")
for i := 0; i < length; i++ {
tempInt := ipInt & 0xFF
ipSplit[length-i-1] = strconv.Itoa(tempInt)
ipInt = ipInt >> 8
}
for i := 0; i < length; i++ {
buffer.WriteString(ipSplit[i])
if i < length-1 {
buffer.WriteString(".")
}
}
return buffer.String()
}
// CompareVersion 比较`x.y.z`类型版本号大小
func CompareVersion(verCurrent, verUpdate string) int {
versionA := strings.Split(verCurrent, ".")
versionB := strings.Split(verUpdate, ".")
for i := len(versionA); i < 4; i++ {
versionA = append(versionA, "0")
}
for i := len(versionB); i < 4; i++ {
versionB = append(versionB, "0")
}
for i := 0; i < 4; i++ {
version1, _ := strconv.Atoi(versionA[i])
version2, _ := strconv.Atoi(versionB[i])
if version1 == version2 {
continue
} else if version1 > version2 {
return 1
} else {
return -1
}
}
return 0
}
// GetLocalIP 获取内网本机ipv4地址
func GetLocalIP() (string, error) {
var address []net.Addr
eth0Interface, err := net.InterfaceByName("eth0")
if err == nil {
address, err = eth0Interface.Addrs()
} else {
address, err = net.InterfaceAddrs()
}
if err != nil {
return "", err
}
for _, addr := range address {
if it, ok := addr.(*net.IPNet); ok && !it.IP.IsLoopback() {
if it.IP.To4() != nil {
return it.IP.String(), nil
}
}
}
return "", err
}
// GetInternetIP 获取外网本机ipv4地址
func GetInternetIP() (string, error) {
resp, err := http.Get("https://api.ipify.org")
if err != nil {
resp, err = http.Get("https://icanhazip.com")
if err != nil {
return "", err
}
}
defer func() {
_ = resp.Body.Close()
}()
s, readErr := io.ReadAll(resp.Body)
if readErr != nil {
return "", readErr
}
return string(s), nil
}
// IsExists 检测指定路径文件或者文件夹是否存在
func IsExists(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
// CheckWebsiteAddr 检查域名是否正确
func CheckWebsiteAddr(addr string) error {
if 0 == len(addr) {
return errors.New("url is empty")
}
parse, err := url.Parse(addr)
if err != nil {
return err
}
if "http" != parse.Scheme && "https" != parse.Scheme {
return errors.New("url Scheme illegal. err:" + parse.Scheme)
}
re := regexp.MustCompile(`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)+([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$`)
u := strings.Split(parse.Host, ":")
if 2 == len(u) && 0 != len(u[1]) {
result := re.FindAllStringSubmatch(u[0], -1)
if result == nil {
return errors.New("url illegal. err:" + u[0])
}
return nil
}
result := re.FindAllStringSubmatch(parse.Host, -1)
if result == nil {
return errors.New("url illegal. err:" + parse.Host)
}
return nil
}
// LoadKeyValConfig 获取本地`a=c\n`类型文件的键值对
func LoadKeyValConfig(text string) map[string]string {
config := make(map[string]string)
r := bufio.NewReader(bytes.NewBufferString(text))
for {
b, _, err := r.ReadLine()
if err != nil {
if err == io.EOF {
break
}
panic(err)
}
s := strings.TrimSpace(string(b))
index := strings.Index(s, "=")
if index < 0 || strings.HasPrefix(s, "#") {
continue
}
key := strings.TrimSpace(s[:index])
if len(key) == 0 {
continue
}
value := strings.TrimSpace(s[index+1:])
if len(value) == 0 {
continue
}
config[key] = value
}
return config
}
// PortIsUse 判断端口是否占用
func PortIsUse(port int) bool {
_, tcpError := net.DialTimeout("tcp", fmt.Sprintf(":%d", port), time.Millisecond*50)
udpAddr, _ := net.ResolveUDPAddr("udp4", fmt.Sprintf(":%d", port))
udpConn, udpError := net.ListenUDP("udp", udpAddr)
if udpConn != nil {
defer func() {
_ = udpConn.Close()
}()
}
return tcpError == nil || udpError != nil
}
// ReplaceInvalidFilenameChars 用下划线替换不合法文件名的字符
func ReplaceInvalidFilenameChars(filename string) string {
pattern := regexp.MustCompile(`[\\/:*?"<>|{}'()!@#$%^&\[\];,+=~·!¥…()—{}、:“”‘’;,《》。?]`)
filename = pattern.ReplaceAllString(filename, "_")
return strings.ReplaceAll(filename, " ", "")
}