486 lines
10 KiB
Go
486 lines
10 KiB
Go
|
|
package utility
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"reflect"
|
|||
|
|
"regexp"
|
|||
|
|
"sort"
|
|||
|
|
"strconv"
|
|||
|
|
"strings"
|
|||
|
|
"unicode/utf8"
|
|||
|
|
"unsafe"
|
|||
|
|
|
|||
|
|
"go.uber.org/zap"
|
|||
|
|
|
|||
|
|
log "github.com/go-admin-team/go-admin-core/logger"
|
|||
|
|
"github.com/shopspring/decimal"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 获取不超过指定长度的字段
|
|||
|
|
func StringCut(s string, maxLength int) string {
|
|||
|
|
if len(s) > maxLength {
|
|||
|
|
return s[:maxLength] // 获取前 maxLength 个字符
|
|||
|
|
}
|
|||
|
|
return s // 如果长度不足,返回原字符串
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FloatToStringZero 去掉多余的小数0,比如0.0245000返回0.0245,return string
|
|||
|
|
func FloatToStringZero(num string) string {
|
|||
|
|
de, _ := decimal.NewFromString(num)
|
|||
|
|
str := de.String()
|
|||
|
|
return str
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IntTostring int to string
|
|||
|
|
func IntTostring(num int) string {
|
|||
|
|
if num == 0 {
|
|||
|
|
return "0"
|
|||
|
|
}
|
|||
|
|
return strconv.Itoa(num)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringLen 获取字符串真实长度
|
|||
|
|
func StringLen(s string) int {
|
|||
|
|
return len([]rune(s))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringIsNil 检测字符串长度是否为0
|
|||
|
|
func StringIsNil(str string) bool {
|
|||
|
|
if len(str) == 0 {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
return len(strings.Trim(str, " ")) == 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringTrim 去前后空格
|
|||
|
|
func StringTrim(str string) string {
|
|||
|
|
return strings.Trim(str, " ")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringAsFloat tries to convert a string to float, and if it can't, just returns zero
|
|||
|
|
// 尝试将字符串转换为浮点数,如果不能,则返回0
|
|||
|
|
func StringAsFloat(s string) float64 {
|
|||
|
|
if len(s) == 0 {
|
|||
|
|
return 0.0
|
|||
|
|
}
|
|||
|
|
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
|||
|
|
return f
|
|||
|
|
}
|
|||
|
|
return 0.0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func StringAsDecimal(s string) decimal.Decimal {
|
|||
|
|
if len(s) == 0 {
|
|||
|
|
return decimal.Zero
|
|||
|
|
}
|
|||
|
|
f, err := decimal.NewFromString(s)
|
|||
|
|
if err != nil {
|
|||
|
|
log.Error("字符串转化decimal失败: ", zap.Error(err))
|
|||
|
|
return decimal.Zero
|
|||
|
|
}
|
|||
|
|
return f
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func StringAsFloatCut(s string, size int32) float64 {
|
|||
|
|
if len(s) == 0 {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
f, err := decimal.NewFromString(s)
|
|||
|
|
if err != nil {
|
|||
|
|
log.Error("字符串转化decimal失败: ", zap.Error(err))
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
d, _ := f.Truncate(size).Float64()
|
|||
|
|
return d
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FloatToString 按保留的小数点位数,去掉多余的小数,return string
|
|||
|
|
func FloatToString(num float64, size int32) string {
|
|||
|
|
if num == 0 {
|
|||
|
|
return getZero(size)
|
|||
|
|
}
|
|||
|
|
de := decimal.NewFromFloat(num)
|
|||
|
|
str := de.Truncate(size).String()
|
|||
|
|
return str
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func getZero(size int32) string {
|
|||
|
|
switch size {
|
|||
|
|
case 0:
|
|||
|
|
return "0"
|
|||
|
|
case 1:
|
|||
|
|
return "0.0"
|
|||
|
|
case 2:
|
|||
|
|
return "0.00"
|
|||
|
|
case 3:
|
|||
|
|
return "0.000"
|
|||
|
|
case 4:
|
|||
|
|
return "0.0000"
|
|||
|
|
case 5:
|
|||
|
|
return "0.00000"
|
|||
|
|
case 6:
|
|||
|
|
return "0.000000"
|
|||
|
|
}
|
|||
|
|
return "0"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func GetGearNumStr(size int32) string {
|
|||
|
|
switch size {
|
|||
|
|
case 0:
|
|||
|
|
return "1"
|
|||
|
|
case 1:
|
|||
|
|
return "0.1"
|
|||
|
|
case 2:
|
|||
|
|
return "0.01"
|
|||
|
|
case 3:
|
|||
|
|
return "0.001"
|
|||
|
|
case 4:
|
|||
|
|
return "0.0001"
|
|||
|
|
case 5:
|
|||
|
|
return "0.00001"
|
|||
|
|
case 6:
|
|||
|
|
return "0.000001"
|
|||
|
|
case 7:
|
|||
|
|
return "0.0000001"
|
|||
|
|
case 8:
|
|||
|
|
return "0.00000001"
|
|||
|
|
}
|
|||
|
|
return "0.1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func FloatToStr(num float64) string {
|
|||
|
|
de := decimal.NewFromFloat(num)
|
|||
|
|
str := de.String()
|
|||
|
|
return str
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringAsInteger returns the integer value extracted from string, or zero
|
|||
|
|
func StringAsInteger(s string) int {
|
|||
|
|
if s == "" {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
if i, err := strconv.ParseInt(s, 10, 32); err == nil {
|
|||
|
|
return int(i)
|
|||
|
|
}
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringAsInt64 returns the int64 value extracted from string, or zero
|
|||
|
|
func StringAsInt64(s string) int64 {
|
|||
|
|
if s == "" {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|||
|
|
return i
|
|||
|
|
}
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func StringAsInt32(s string) int32 {
|
|||
|
|
if s == "" {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|||
|
|
return int32(i)
|
|||
|
|
}
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringToDecimal String To Decimal
|
|||
|
|
func StringToDecimal(val string) decimal.Decimal {
|
|||
|
|
cleanedNum := strings.TrimRight(val, "\x00") // 去除空字符
|
|||
|
|
cleanedNum = strings.TrimSpace(cleanedNum) // 去除空格
|
|||
|
|
cleanedNum = strings.ReplaceAll(cleanedNum, ",", "") // 去除逗号
|
|||
|
|
d, err := decimal.NewFromString(cleanedNum)
|
|||
|
|
if err != nil {
|
|||
|
|
return decimal.Zero
|
|||
|
|
}
|
|||
|
|
return d
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringToInt String => int
|
|||
|
|
func StringToInt(val string) int {
|
|||
|
|
i, err := strconv.Atoi(val)
|
|||
|
|
if err != nil {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
return i
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StringToFloat64 String => Float64
|
|||
|
|
func StringToFloat64(val string) float64 {
|
|||
|
|
d, err := strconv.ParseFloat(val, 64)
|
|||
|
|
if err != nil {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
return d
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ToLower 返回小写字符串
|
|||
|
|
func ToLower(str string) string {
|
|||
|
|
return strings.ToLower(str)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ToUpper 返回大写字符串
|
|||
|
|
func ToUpper(str string) string {
|
|||
|
|
return strings.ToUpper(str)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IntToString int to string
|
|||
|
|
func IntToString(num int) string {
|
|||
|
|
if num == 0 {
|
|||
|
|
return "0"
|
|||
|
|
}
|
|||
|
|
return strconv.Itoa(num)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CheckPhone returns true if a given sequence has between 9 and 14 digits
|
|||
|
|
func CheckPhone(phone string, acceptEmpty bool) bool {
|
|||
|
|
phone = OnlyDigits(phone)
|
|||
|
|
|
|||
|
|
return (acceptEmpty && (phone == "")) || ((len([]rune(phone)) >= 9) && (len([]rune(phone)) <= 14))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// OnlyDigits returns only the numbers from the given string, after strip all the rest ( letters, spaces, etc. )
|
|||
|
|
func OnlyDigits(sequence string) string {
|
|||
|
|
if utf8.RuneCountInString(sequence) > 0 {
|
|||
|
|
re, _ := regexp.Compile(`[\D]`)
|
|||
|
|
|
|||
|
|
sequence = re.ReplaceAllString(sequence, "")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return sequence
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CheckEmail returns true if the given sequence is a valid email address
|
|||
|
|
// See https://tools.ietf.org/html/rfc2822#section-3.4.1 for details about email address anatomy
|
|||
|
|
func CheckEmail(email string) bool {
|
|||
|
|
if email == "" {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
re := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
|||
|
|
|
|||
|
|
return re.MatchString(email)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsNumericType checks if an interface's concrete type corresponds to some of golang native numeric types
|
|||
|
|
func IsNumericType(x interface{}) bool {
|
|||
|
|
switch x.(type) {
|
|||
|
|
case uint:
|
|||
|
|
return true
|
|||
|
|
case uint8: // Or byte
|
|||
|
|
return true
|
|||
|
|
case uint16:
|
|||
|
|
return true
|
|||
|
|
case uint32:
|
|||
|
|
return true
|
|||
|
|
case uint64:
|
|||
|
|
return true
|
|||
|
|
case int:
|
|||
|
|
return true
|
|||
|
|
case int8:
|
|||
|
|
return true
|
|||
|
|
case int16:
|
|||
|
|
return true
|
|||
|
|
case int32:
|
|||
|
|
return true
|
|||
|
|
case float32:
|
|||
|
|
return true
|
|||
|
|
case float64:
|
|||
|
|
return true
|
|||
|
|
case complex64:
|
|||
|
|
return true
|
|||
|
|
case complex128:
|
|||
|
|
return true
|
|||
|
|
default:
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// B2S converts byte slice to a string without memory allocation.
|
|||
|
|
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
|
|||
|
|
//
|
|||
|
|
// Note it may break if string and/or slice header will change
|
|||
|
|
// in the future go versions.
|
|||
|
|
func B2S(b []byte) string {
|
|||
|
|
return *(*string)(unsafe.Pointer(&b))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// S2B converts string to a byte slice without memory allocation.
|
|||
|
|
// Note it may break if string and/or slice header will change
|
|||
|
|
// in the future go versions.
|
|||
|
|
func S2B(s string) (b []byte) {
|
|||
|
|
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|||
|
|
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
|
|||
|
|
bh.Data = sh.Data
|
|||
|
|
bh.Len = sh.Len
|
|||
|
|
bh.Cap = sh.Len
|
|||
|
|
return b
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Int64ToString int64 转到string
|
|||
|
|
func Int64ToString(num int64) string {
|
|||
|
|
if num == 0 {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
return strconv.FormatInt(num, 10)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Float64ToString Float64 转 string
|
|||
|
|
// prec: 小数位数 -1 为全保留 与 FloatCutStr 不同的是 这里会四舍五入
|
|||
|
|
func Float64ToString(num float64, prec int32) string {
|
|||
|
|
return strconv.FormatFloat(num, 'f', int(prec), 64)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SliceRemoveDuplicates 除去[]string数组重复的数据
|
|||
|
|
func SliceRemoveDuplicates(slice []string) []string {
|
|||
|
|
sort.Strings(slice)
|
|||
|
|
i := 0
|
|||
|
|
var j int
|
|||
|
|
for {
|
|||
|
|
if i >= len(slice)-1 {
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for j = i + 1; j < len(slice) && slice[i] == slice[j]; j++ {
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
slice = append(slice[:i+1], slice[j:]...)
|
|||
|
|
i++
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return slice
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func GetSymbolIdStr(coinId, currId string) string {
|
|||
|
|
return fmt.Sprintf("%v/%v", coinId, currId)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func GetSymbolCoinIdAndCurrId(symbolIdStr string) (string, string) {
|
|||
|
|
l := strings.Split(symbolIdStr, "/")
|
|||
|
|
return l[0], l[1]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 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)
|
|||
|
|
}
|
|||
|
|
func FilteredSQLInject(to_match_str string) bool {
|
|||
|
|
//过滤 ‘
|
|||
|
|
//ORACLE 注解 -- /**/
|
|||
|
|
//关键字过滤 update ,delete
|
|||
|
|
// 正则的字符串, 不能用 " " 因为" "里面的内容会转义
|
|||
|
|
str := `(?:')|(?:--)|(/\*(?:.|[\n\r])*?\*/)|((select|update|and|or|delete|insert|trancate|char|chr|into|substr|ascii|declare|exec|count|master|into|drop|execute))`
|
|||
|
|
re, err := regexp.Compile(str)
|
|||
|
|
if err != nil {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
return re.MatchString(to_match_str)
|
|||
|
|
}
|
|||
|
|
func TrimHtml(src string) string {
|
|||
|
|
//将HTML标签全转换成小写
|
|||
|
|
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
|
|||
|
|
src = re.ReplaceAllStringFunc(src, strings.ToLower)
|
|||
|
|
//去除STYLE
|
|||
|
|
re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
|
|||
|
|
src = re.ReplaceAllString(src, "")
|
|||
|
|
//去除SCRIPT
|
|||
|
|
re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
|
|||
|
|
src = re.ReplaceAllString(src, "")
|
|||
|
|
//去除所有尖括号内的HTML代码,并换成换行符
|
|||
|
|
re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
|
|||
|
|
src = re.ReplaceAllString(src, "\n")
|
|||
|
|
//去除连续的换行符
|
|||
|
|
re, _ = regexp.Compile("\\s{2,}")
|
|||
|
|
src = re.ReplaceAllString(src, "\n")
|
|||
|
|
return strings.TrimSpace(src)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ReplaceImages 过滤掉图片
|
|||
|
|
func ReplaceImages(htmls string) string {
|
|||
|
|
result := htmls
|
|||
|
|
regx := `<img[^>]*src[="'s]+[^.]*/([^.]+).[^"']+["']?[^>]*>`
|
|||
|
|
var imgRE = regexp.MustCompile(regx)
|
|||
|
|
imgs := imgRE.FindAllStringSubmatch(htmls, -1)
|
|||
|
|
for i := range imgs {
|
|||
|
|
v := imgs[i]
|
|||
|
|
result = strings.ReplaceAll(result, v[0], "")
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// KeySubString 文章搜索专用
|
|||
|
|
func KeySubString(key, value string, leng int) string {
|
|||
|
|
b := ReplaceImages(value)
|
|||
|
|
pos := strings.Index(b, key)
|
|||
|
|
if pos < 0 {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
start := b[0:pos]
|
|||
|
|
end := b[pos:]
|
|||
|
|
out := Substr(end, leng)
|
|||
|
|
return start + out
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Substr 截取字符串
|
|||
|
|
func Substr(s string, l int) string {
|
|||
|
|
if len(s) <= l {
|
|||
|
|
return s
|
|||
|
|
}
|
|||
|
|
ss, sl, rl, rs := "", 0, 0, []rune(s)
|
|||
|
|
for _, r := range rs {
|
|||
|
|
rint := int(r)
|
|||
|
|
if rint < 128 {
|
|||
|
|
rl = 1
|
|||
|
|
} else {
|
|||
|
|
rl = 2
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if sl+rl > l {
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
sl += rl
|
|||
|
|
ss += string(r)
|
|||
|
|
}
|
|||
|
|
return ss
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
根据字符串获取小数位数
|
|||
|
|
*/
|
|||
|
|
func GetPrecision(value string) int {
|
|||
|
|
// 去掉末尾的多余零
|
|||
|
|
value = strings.TrimRight(value, "0")
|
|||
|
|
|
|||
|
|
// 找到小数点的位置
|
|||
|
|
decimalPos := strings.Index(value, ".")
|
|||
|
|
|
|||
|
|
if decimalPos == -1 {
|
|||
|
|
// 如果没有小数点,说明是整数,精度为0
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算小数点后的位数
|
|||
|
|
return len(value) - decimalPos - 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 替换字符串后缀
|
|||
|
|
func ReplaceSuffix(text, oldSuffix, newSuffix string) string {
|
|||
|
|
if strings.HasSuffix(text, oldSuffix) {
|
|||
|
|
return text[:len(text)-len(oldSuffix)] + newSuffix
|
|||
|
|
}
|
|||
|
|
return text
|
|||
|
|
}
|