Golang Tools

URL

// url 解码、加码
str, err = url.QueryUnescape(str)
str := url.QueryEscape(str)

正则校验

// 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)

}

// 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)
}

日志类

  • 获取 所在文件、所在函数、所在行
package main

import (
	"fmt"
	"path"
	"runtime"
)

func main() {
	a, b, c := GetLocation()
	fmt.Println("---------------------")
	fmt.Println(a) // main.go
	fmt.Println("---------------------")
	fmt.Println(b) // main.main
	fmt.Println("---------------------")
	fmt.Println(c) // 10
	fmt.Println("---------------------")

}

func GetLocation() (fileName, funcName string, line int) {
	skip := 1
	pc, file, line, ok := runtime.Caller(skip)
	if !ok {
		fmt.Println("get info failed")
		return
	}
	// fmt.Println(pc, file)
	fileName = path.Base(file)
	funcName = runtime.FuncForPC(pc).Name()
	return
}

时间、日志 类

  • 计算 两个日期 之间的 天数
// E: start := "2021-06-28"   end := "2021-07-01"
func SubDays(start, end string) (int, error) {
	Start, err := time.ParseInLocation("2006-01-02", start, time.Local)
	if err != nil {
		return 0, errors.New("时间数据格式异常")
	}
	End, err := time.ParseInLocation("2006-01-02", end, time.Local)
	if err != nil {
		return 0, errors.New("时间数据格式异常")
	}

	day := int(End.Sub(Start).Hours() / 24)

	// 计算在被24整除外的时间是否存在跨自然日
	if int(End.Sub(Start).Milliseconds())%86400000 > int(86400000-Start.Unix()%86400000) {
		day += 1
	}
	return day, nil
}
  • 计算 两个日期 之间的 月数
// F: start := "2020-01-03"   end := "2020-02-01"
func SubMonth(Start, End string) (month int, err error) {
	start, err := time.ParseInLocation("2006-01-02", Start, time.Local)
	if err != nil {
		return 0, err
	}
	end, err := time.ParseInLocation("2006-01-02", End, time.Local)
	if err != nil {
		return 0, err
	}

	y1 := end.Year()
	y2 := start.Year()
	m1 := int(end.Month())
	m2 := int(start.Month())
	d1 := end.Day()
	d2 := start.Day()

	yearInterval := y1 - y2
	// 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
	if m1 < m2 || m1 == m2 && d1 < d2 {
		yearInterval--
	}
	// 获取月数差值
	monthInterval := (m1 + 12) - m2
	if d1 < d2 {
		monthInterval--
	}
	monthInterval %= 12
	month = yearInterval*12 + monthInterval
	return month, nil
}
  • 计算 哪一年的 哪一个月 有多少天
// year:2004 month:12
func GetYearMonthToDay(year, month int) int {
	// 有31天的月份
	day31 := map[int]bool{
		1:  true,
		3:  true,
		5:  true,
		7:  true,
		8:  true,
		10: true,
		12: true,
	}
	if day31[month] {
		return 31
	}
	// 有30天的月份
	day30 := map[int]bool{
		4:  true,
		6:  true,
		9:  true,
		11: true,
	}
	if day30[month] {
		return 30
	}
	// 计算是平年还是闰年
	if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
		// 得出2月的天数
		return 29
	}
	// 得出2月的天数
	return 28
}
  • 获取 指定 日期月份的 第一天 是 周几
func GetFirstDateOfMonth(d time.Time) int {
	d = d.AddDate(0, 0, -d.Day()+1)
	weeks := time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location()).Weekday()
	return int(weeks)
}

加密

  • md5 加密
func MD5(data []byte) string {
	s := fmt.Sprintf("%x", md5.Sum(data))
	return s
}

随机数

  • 生成n位随机数
func RandNum(n int) string {
	rand.Seed(time.Now().UnixNano())
	var s string
	for i := 0; i < n; i++ {
		tmp := strconv.FormatInt(int64(rand.Intn(8)+1), 10)
		s += tmp
	}
	return s
}

数字处理

func RoundFloat(f float64, n int) float64 {
	n10 := math.Pow10(n)
	return math.Trunc((f+0.5/n10)*n10) / n10
}

经纬度

func GetDistance(lng1, lat1, lng2, lat2 float64) float64 {
	radius := 6371000.0 //地球半径为R=6371km
	rad := math.Pi / 180.0
	lat1 = lat1 * rad
	lng1 = lng1 * rad
	lat2 = lat2 * rad
	lng2 = lng2 * rad
	theta := lng2 - lng1
	dist := math.Acos(math.Sin(lat1)*math.Sin(lat2) + math.Cos(lat1)*math.Cos(lat2)*math.Cos(theta))
	// 单位为:千米(公里)
	distance := dist * radius / 1000
	return RoundFloat(distance, 1)
}

字符处理

  • 大驼峰 —》小驼峰
func D2X(str string) string {
	// step1:找出所有的大写字母
	s := []byte(str)
	v := regexp.MustCompile(`[A-Z]{1}`)
	value := v.FindAll(s, -1)

	// step2: 遍历替换
	var res string
	for i := 0; i < len(value); i++ {
		tmp := string(value[i])
		insta := "_" + strings.ToLower(tmp)
		// 这个地方其实用递归倒是挺好
		if i == 0 {
			res = strings.Replace(str, tmp, insta, 1)

		} else {
			res = strings.Replace(res, tmp, insta, 1)
		}
	}
	return strings.Trim(res, "_")
}

文件处理类

  • 获取MP3文件的音频总时长
package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/tosone/minimp3"
)

func main() {

	res, err := GetMP3FileDuration("123.mp3")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(res)
}

// filePath: 文件路径
// seconds:返回该文件 有多少秒
func GetMP3FileDuration(filePath string) (seconds int, err error) {
	// 格式校验
	filePathByte := strings.Split(filePath, ".")
	if filePathByte[len(filePathByte)-1] != "mp3" {
		err = fmt.Errorf("文件格式不是mp3格式")
		return 0, err
	}

	ff, err := os.Open(filePath)
	if err != nil {
		return 0, err
	}

	content, err := ioutil.ReadAll(ff)
	if err != nil {
		return 0, err
	}

	dec, _, err := minimp3.DecodeFull(content)
	if err != nil {
		return 0, err
	}
	// 音乐时长 = (文件大小(byte) - 128(ID3信息)) * 8(to bit) / (码率(kbps b:bit) * 1000)(kilo bit to bit)
	seconds = (len(content) - 128) * 8 / (dec.Kbps * 1000)
	return seconds, nil
}

密码类

AES

AES是取代其前任DES而成为新标准的一种对称密码算法,是公开的目前 对称算法 里面 效率 和 安全级别 最高的.
在AES的规格中, 密钥长度只有128\192\256 bit三种. 分别对应16\24\32字节.
注意: 在Go 中只能使用长度为16字节的密钥.

package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"fmt"
)

func main() {
	strjson := `{"name": "tom", "age":12}`

	res, err := AesLock([]byte(strjson))
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(res)

	res2, _ := AesUnlock(res)
	fmt.Println(res2)

}

// ============================================

var (
	key = []byte("abcdabcdabcdabcd") // 16位秘钥 对应 AES128 加密
	iv  = []byte("0000000000000000")// 初始化向量, 默认都是0、长度位16
)

func AesLock(origData []byte) (string, error) {
	// 基础校验,长度校验
	if key == nil || len(key) != 16 {
		return "", fmt.Errorf("key is left")
	}
	if iv != nil && len(iv) != 16 {
		return "", fmt.Errorf("iv is left")
	}

	// step1: 通过秘钥 获取一个 密码块
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}
	// 获取 密码块(每一小块) 的长度
	blockSize := block.BlockSize()

	// step2: 明文 数据填充  (对应解密时的 密文 数据清洗)
	padding := blockSize - len(origData)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	origData = append(origData, padtext...)

	// step3: 块模式、 密文原
	// NewCBCEncrypter返回一个 块模式,该 模式使 用给定的 块 以 密码块链接模式 进行加密。
	// iv的长度必须与 区块 的区块大小相同。
	blockMode := cipher.NewCBCEncrypter(block, iv[:blockSize])

	// 生成 密文原 crypted
	crypted := make([]byte, len(origData))
	blockMode.CryptBlocks(crypted, origData)

	// step4: 将 密文源 以 base64 的形式 解析为 字符串
	return base64.RawStdEncoding.EncodeToString(crypted), nil
}

func AesUnlock(secret string) (string, error) {
	// step1: 将 密文 以 base64 的形式 解析 获取到 密文源
	crypted, err := base64.RawStdEncoding.DecodeString(secret)
	if err != nil {
		return "", err
	}

	// step2: 通过秘钥 获取一个 密码块
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}
	// 获取 密码块(每一小块) 的长度
	blockSize := block.BlockSize()

	// step3: 块模式
	// 块模式: NewCBCEncrypter返回一个 块模式,该 模式使 用给定的 块 以 密码块链接模式 进行加密。
	// iv的长度必须与 区块 的区块大小相同。
	blockMode := cipher.NewCBCDecrypter(block, iv[:blockSize])

	// step4: 数据清洗
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)
	length := len(origData)
	unpadding := int(origData[length-1])
	origData = origData[:(length - unpadding)]

	return string(origData), nil
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值