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
}