Fetch the repository succeeded.
package zlib
import (
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/gob"
"encoding/hex"
"errors"
"fmt"
"hash"
"hash/crc32"
"html"
"io"
"io/ioutil"
"math"
"math/rand"
"net/url"
"regexp"
"strconv"
"strings"
"time"
"unicode"
"unicode/utf8"
crand "crypto/rand"
xhtml "golang.org/x/net/html"
"golang.org/x/net/html/charset"
"golang.org/x/text/cases"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/encoding/traditionalchinese"
"golang.org/x/text/language"
"golang.org/x/text/transform"
"golang.org/x/text/width"
)
func StringReplace(text string, _old string, _new string) string {
if len(text) == 0 {
return ""
}
if len(_old) == 0 {
return text
}
if len(_new) == 0 {
_new = ""
}
text = strings.Replace(text, _old, _new, -1)
return text
}
func StringReplaceMulti(str string, fromTo ...string) string {
if len(fromTo)%2 != 0 {
panic("Need even number of fromTo arguments")
}
for i := 0; i < len(fromTo); i += 2 {
str = strings.Replace(str, fromTo[i], fromTo[i+1], -1)
}
return str
}
func StringReplaceRange(text string, _start int, _end int, _new string) string {
if len(text) <= _end {
_end = len(text) - 1
}
if len(_new) == 0 {
_new = "**"
}
return text[:_start] + _new + text[_end:]
}
// StringFilterInput 过滤Input输入的值
// 转义%、"、'、(、)、!、/、^、*、.、
func StringFilterInput(_value string) string {
value := _value
blackArray := [...]string{ // 这些符号将被转义
"%", "(", ")", "!", "/", "^", "*", ".", "|", "=",
}
changArray := [...]string{ // 这些符号将被替代
"select", "delete", "char", "insert", "count", "exec", "declare", "update",
}
for i := 0; i < len(blackArray); i++ {
txt := blackArray[i]
value = StringReplace(value, txt, EncodeURL(txt))
}
for j := 0; j < len(changArray); j++ {
txt := changArray[j]
value = StringReplace(value, txt, "_"+txt)
}
value = html.EscapeString(value) // xss
return value
}
// StringHideValue 隐藏/替换字符串中的某些字符
// 如隐藏手机号:185*******6,调用Common.HideStringValue("18511111111", 3, 10, "*")
func StringHideValue(_string string, start int, end int, replaceValue string) string {
if len(replaceValue) == 0 {
replaceValue = "*"
}
blackString := _string[start:end]
replace := ""
for i := 0; i < len(blackString); i++ {
replace = replace + replaceValue
}
return strings.Replace(_string, blackString, replace, -1)
}
func UcFirst(_string string) string {
if len(_string) == 0 {
return ""
}
s := []rune(_string)
if s[0] >= 97 && s[0] <= 122 {
s[0] -= 32
}
return string(s)
}
func LcFirst(_string string) string {
if len(_string) == 0 {
return ""
}
s := []rune(_string)
if s[0] >= 65 && s[0] <= 90 {
s[0] += 32
}
return string(s)
}
func MapString(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))
for i, v := range vs {
vsm[i] = f(v)
}
return vsm
}
func RightPad(s string, padStr string, overallLen int) string {
var padCountInt = 1 + ((overallLen - len(padStr)) / len(padStr))
var retStr = s + strings.Repeat(padStr, padCountInt)
return retStr[:overallLen]
}
func LeftPad(s string, padStr string, overallLen int) string {
var padCountInt = 1 + ((overallLen - len(padStr)) / len(padStr))
var retStr = strings.Repeat(padStr, padCountInt) + s
return retStr[(len(retStr) - overallLen):]
}
// CamelCaseToLowerCase 驼峰转为小写.
func CamelCaseToLowerCase(str string, connector rune) string {
if len(str) == 0 {
return ""
}
buf := &bytes.Buffer{}
var prev, r0, r1 rune
var size int
r0 = connector
for len(str) > 0 {
prev = r0
r0, size = utf8.DecodeRuneInString(str)
str = str[size:]
switch {
case r0 == utf8.RuneError:
continue
case unicode.IsUpper(r0):
if prev != connector && !unicode.IsNumber(prev) {
buf.WriteRune(connector)
}
buf.WriteRune(unicode.ToLower(r0))
if len(str) == 0 {
break
}
r0, size = utf8.DecodeRuneInString(str)
str = str[size:]
if !unicode.IsUpper(r0) {
buf.WriteRune(r0)
break
}
// find next non-upper-case character and insert connector properly.
// it's designed to convert `HTTPServer` to `http_server`.
// if there are more than 2 adjacent upper case characters in a word,
// treat them as an abbreviation plus a normal word.
for len(str) > 0 {
r1 = r0
r0, size = utf8.DecodeRuneInString(str)
str = str[size:]
if r0 == utf8.RuneError {
buf.WriteRune(unicode.ToLower(r1))
break
}
if !unicode.IsUpper(r0) {
if isCaseConnector(r0) {
r0 = connector
buf.WriteRune(unicode.ToLower(r1))
} else if unicode.IsNumber(r0) {
// treat a number as an upper case rune
// so that both `http2xx` and `HTTP2XX` can be converted to `http_2xx`.
buf.WriteRune(unicode.ToLower(r1))
buf.WriteRune(connector)
buf.WriteRune(r0)
} else {
buf.WriteRune(connector)
buf.WriteRune(unicode.ToLower(r1))
buf.WriteRune(r0)
}
break
}
buf.WriteRune(unicode.ToLower(r1))
}
if len(str) == 0 || r0 == connector {
buf.WriteRune(unicode.ToLower(r0))
}
case unicode.IsNumber(r0):
if prev != connector && !unicode.IsNumber(prev) {
buf.WriteRune(connector)
}
buf.WriteRune(r0)
default:
if isCaseConnector(r0) {
r0 = connector
}
buf.WriteRune(r0)
}
}
return buf.String()
}
// getIntersectStrings 获取两个字符串相同部分的切片.
// minLen为子串最小长度,为0则不限制.
func GetIntersectStrings(minLen int, str1, str2 string) (res []string) {
var lenA, lenB, runesLen int
var runes []rune
var longStr, itm string
var chkMap = make(map[string]bool)
var chk, ok bool
lenA = len(str1)
lenB = len(str2)
if lenA == 0 || lenB == 0 {
return
}
if lenA > lenB {
longStr = str1
runes = []rune(str2)
} else {
longStr = str2
runes = []rune(str1)
}
runesLen = len(runes)
for i := 0; i < runesLen; i++ {
for j := i + 1; j <= runesLen; j++ {
itm = string(runes[i:j])
if minLen == 0 || (minLen > 0 && len(itm) >= minLen) {
_, ok = chkMap[itm]
if !ok {
chk = strings.Contains(longStr, itm)
chkMap[itm] = true
if chk {
res = append(res, itm)
}
}
}
}
}
return
}
// longestSameString 获取两个字符串最长相同的子串.
func GetLongestSameString(str1, str2 string) (res string) {
var resLen, itmLen int
strs := GetIntersectStrings(0, str1, str2)
if len(strs) > 0 {
res = strs[0]
resLen = len(res)
for _, v := range strs {
itmLen = len(v)
if itmLen > resLen {
res = v
resLen = itmLen
}
}
}
return
}
// SimilarText 计算两个字符串的相似度;返回在两个字符串中匹配字符的数目,以及相似程度百分数.
func SimilarText(str1, str2 string, len1, len2 int) int {
var sum, max int
pos1, pos2 := 0, 0
// Find the longest segment of the same section in two strings
for i := 0; i < len1; i++ {
for j := 0; j < len2; j++ {
for l := 0; (i+l < len1) && (j+l < len2) && (str1[i+l] == str2[j+l]); l++ {
if l+1 > max {
max = l + 1
pos1 = i
pos2 = j
}
}
}
}
if sum = max; sum > 0 {
if pos1 > 0 && pos2 > 0 {
sum += SimilarText(str1, str2, pos1, pos2)
}
if (pos1+max < len1) && (pos2+max < len2) {
s1 := []byte(str1)
s2 := []byte(str2)
sum += SimilarText(string(s1[pos1+max:]), string(s2[pos2+max:]), len1-pos1-max, len2-pos2-max)
}
}
return sum
}
// ChunkBytes 将字节切片分割为多个小块.其中size为每块的长度.
func ChunkBytes(bs []byte, size int) [][]byte {
bsLen := len(bs)
if bsLen == 0 || size <= 0 {
return nil
} else if bsLen < size {
return [][]byte{bs}
}
var start, last int
pages := int(math.Ceil(float64(bsLen) / float64(size)))
res := make([][]byte, pages)
for i := 0; i < pages; i++ {
last = start + size
if last > bsLen {
res[i] = bs[start:]
} else {
res[i] = bs[start:last]
}
start = last
}
return res
}
// shaXByte 计算字节切片的 shaX 散列值,x为1/256/512.
func shaXByte(str []byte, x uint16) []byte {
var h hash.Hash
switch x {
case 1:
h = sha1.New()
case 256:
h = sha256.New()
case 512:
h = sha512.New()
default:
panic(fmt.Sprintf("[shaXByte]`x must be in [1, 256, 512]; but: %d", x))
}
_, err := h.Write(str)
if err != nil {
return nil
}
hBytes := h.Sum(nil)
res := make([]byte, hex.EncodedLen(len(hBytes)))
hex.Encode(res, hBytes)
return res
}
// ShaX 计算字符串的 shaX 散列值,x为1/256/512 .
func ShaX(str string, x uint16) string {
return string(ShaXByte([]byte(str), x))
}
// IsSha1 是否Sha1值.
func IsSha1(str string) bool {
return str != "" && RegSha1.MatchString(str)
}
// IsSha256 是否Sha256值.
func IsSha256(str string) bool {
return str != "" && RegSha256.MatchString(str)
}
// IsSha512 是否Sha512值.
func IsSha512(str string) bool {
return str != "" && RegSha512.MatchString(str)
}
// Index 查找子串sub在字符串str中第一次出现的位置,不存在则返回-1;
// ignoreCase为是否忽略大小写.
func Index(str, sub string, ignoreCase bool) int {
if str == "" || sub == "" {
return -1
}
if ignoreCase {
str = strings.ToLower(str)
sub = strings.ToLower(sub)
}
return strings.Index(str, sub)
}
// LastIndex 查找子串sub在字符串str中最后一次出现的位置,不存在则返回-1;
// ignoreCase为是否忽略大小写.
func LastIndex(str, sub string, ignoreCase bool) int {
if str == "" || sub == "" {
return -1
}
if ignoreCase {
str = strings.ToLower(str)
sub = strings.ToLower(sub)
}
return strings.LastIndex(str, sub)
}
// Addslashes 使用反斜线引用字符串.
func Addslashes(str string) string {
var buf bytes.Buffer
for _, char := range str {
switch char {
case '\'', '"', '\\':
buf.WriteRune('\\')
}
buf.WriteRune(char)
}
return buf.String()
}
// Stripslashes 反引用一个引用字符串.
func Stripslashes(str string) string {
var buf bytes.Buffer
l, skip := len(str), false
for i, char := range str {
if skip {
skip = false
} else if char == '\\' {
if i+1 < l && str[i+1] == '\\' {
skip = true
}
continue
}
buf.WriteRune(char)
}
return buf.String()
}
// Utf8ToGbk UTF-8转GBK编码.
func Utf8ToGbk(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder())
d, e := io.ReadAll(reader)
return d, e
}
// StringToUTF8 将指定字符编码的字符串转为utf8
func StringToUTF8(cont, srcEncoding string) (str string, err error) {
var b []byte
in := strings.NewReader(cont)
switch strings.ToUpper(srcEncoding) {
case "GB18030", "GB-18030":
b, err = ioutil.ReadAll(transform.NewReader(in, simplifiedchinese.GB18030.NewDecoder()))
case "GBK", "GB2312", "GB-2312":
b, err = ioutil.ReadAll(transform.NewReader(in, simplifiedchinese.GBK.NewDecoder()))
case "HZGB2312", "HZ-GB2312":
b, err = ioutil.ReadAll(transform.NewReader(in, simplifiedchinese.HZGB2312.NewDecoder()))
case "BIG":
b, err = ioutil.ReadAll(transform.NewReader(in, traditionalchinese.Big5.NewDecoder()))
case "UTF8", "UTF-8":
str = cont
return
default:
var rio io.Reader
rio, err = charset.NewReader(strings.NewReader(cont), srcEncoding)
if err != nil {
return
}
b, err = ioutil.ReadAll(rio)
}
str = string(b)
return
}
// GbkToUtf8 GBK转UTF-8编码.
func GbkToUtf8(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
d, e := io.ReadAll(reader)
return d, e
}
// IsUtf8 字符串是否UTF-8编码.
func IsUtf8(s []byte) bool {
return utf8.Valid(s)
}
// IsGbk 字符串是否GBK编码.
func IsGbk(s []byte) (res bool) {
length := len(s)
var i, j int
for i < length {
j = i + 1
//大于127的使用双字节编码,且落在gbk编码范围内的字符
//GBK中每个汉字包含两个字节,第一个字节(首字节)的范围是0x81-0xFE(即129-254),第二个字节(尾字节)的范围是0x40-0xFE(即64-254)
if s[i] > 0x7f && j < length {
if s[i] >= 0x81 &&
s[i] <= 0xfe &&
s[j] >= 0x40 &&
s[j] <= 0xfe {
i += 2
res = true
} else {
res = false
break
}
} else {
i++
}
}
return
}
// StartsWith 字符串str是否以sub开头.
func StartsWith(str, sub string, ignoreCase bool) bool {
if str != "" && sub != "" {
i := Index(str, sub, ignoreCase)
return i == 0
}
return false
}
// StartsWiths 字符串str是否以subs其中之一为开头.
func StartsWiths(str string, subs []string, ignoreCase bool) (res bool) {
for _, sub := range subs {
res = StartsWith(str, sub, ignoreCase)
if res {
break
}
}
return
}
// EndsWith 字符串str是否以sub结尾.
func EndsWith(str, sub string, ignoreCase bool) bool {
if str != "" && sub != "" {
i := LastIndex(str, sub, ignoreCase)
return i != -1 && (len(str)-len(sub)) == i
}
return false
}
// EndsWiths 字符串str是否以subs其中之一为结尾.
func EndsWiths(str string, subs []string, ignoreCase bool) (res bool) {
for _, sub := range subs {
res = EndsWith(str, sub, ignoreCase)
if res {
break
}
}
return
}
// Trim 去除字符串首尾处的空白字符(或者其他字符).
// characterMask为要修剪的字符.
func Trim(str string, characterMask ...string) string {
mask := getTrimMask(characterMask)
return strings.Trim(str, mask)
}
// Ltrim 删除字符串开头的空白字符(或其他字符).
// characterMask为要修剪的字符.
func Ltrim(str string, characterMask ...string) string {
mask := getTrimMask(characterMask)
return strings.TrimLeft(str, mask)
}
// Rtrim 删除字符串末端的空白字符(或者其他字符).
// characterMask为要修剪的字符.
func Rtrim(str string, characterMask ...string) string {
mask := getTrimMask(characterMask)
return strings.TrimRight(str, mask)
}
// TrimBOM 移除字符串中的BOM
func TrimBOM(str []byte) []byte {
return bytes.Trim(str, bomChars)
}
// Jsonp2Json 将jsonp转为json串.
// Example: forbar({a:"1",b:2}) to {"a":"1","b":2}
func Jsonp2Json(str string) (string, error) {
start := strings.Index(str, "(")
end := strings.LastIndex(str, ")")
if start == -1 || end == -1 {
return "", errors.New("[Jsonp2Json] invalid jsonp.")
}
start += 1
if start >= end {
return "", errors.New("[Jsonp2Json] invalid jsonp.")
}
res := str[start:end]
return res, nil
}
// Strpos 查找字符串首次出现的位置,找不到时返回-1.
// haystack在该字符串中进行查找,needle要查找的字符串;
// offset起始位置,为负数时时,搜索会从字符串结尾指定字符数开始.
func Strpos(haystack, needle string, offset int) int {
length := len(haystack)
if length == 0 || offset > length || -offset > length {
return -1
}
if offset < 0 {
offset += length
}
pos := strings.Index(haystack[offset:], needle)
if pos == -1 {
return -1
}
return pos + offset
}
// Stripos 查找字符串首次出现的位置(不区分大小写),找不到时返回-1.
// haystack在该字符串中进行查找,needle要查找的字符串;
// offset起始位置,为负数时时,搜索会从字符串结尾指定字符数开始.
func Stripos(haystack, needle string, offset int) int {
length := len(haystack)
if length == 0 || offset > length || -offset > length {
return -1
}
if offset < 0 {
offset += length
}
pos := Index(haystack[offset:], needle, true)
if pos == -1 {
return -1
}
return pos + offset
}
// Strrpos 查找指定字符串在目标字符串中最后一次出现的位置.
func Strrpos(haystack, needle string, offset int) int {
pos, length := 0, len(haystack)
if length == 0 || offset > length || -offset > length {
return -1
}
if offset < 0 {
haystack = haystack[:offset+length+1]
} else {
haystack = haystack[offset:]
}
pos = strings.LastIndex(haystack, needle)
if offset > 0 && pos != -1 {
pos += offset
}
return pos
}
// Strripos 查找指定字符串在目标字符串中最后一次出现的位置(不区分大小写).
func Strripos(haystack, needle string, offset int) int {
pos, length := 0, len(haystack)
if length == 0 || offset > length || -offset > length {
return -1
}
if offset < 0 {
haystack = haystack[:offset+length+1]
} else {
haystack = haystack[offset:]
}
pos = LastIndex(haystack, needle, true)
if offset > 0 && pos != -1 {
pos += offset
}
return pos
}
// Dstrpos 检查字符串str是否包含数组arr的元素之一,返回检查结果和匹配的字符串.
// chkCase为是否检查大小写.
func Dstrpos(str string, arr []string, chkCase bool) (bool, string) {
if len(str) == 0 || len(arr) == 0 {
return false, ""
}
for _, v := range arr {
if (chkCase && Strpos(str, v, 0) != -1) || (!chkCase && Stripos(str, v, 0) != -1) {
return true, v
}
}
return false, ""
}
// Nl2br 将换行符转换为br标签.
func Nl2br(str string) string {
return strings.Replace(str, "\n", "<br />", -1)
}
// Br2nl 将br标签转换为换行符.
func Br2nl(str string) string {
// <br> , <br /> , <br/>
// <BR> , <BR /> , <BR/>
l := len(str)
buf := make([]byte, 0, l) //prealloca
for i := 0; i < l; i++ {
switch str[i] {
case 60: //<
if l >= i+3 {
/*
b = 98
B = 66
r = 82
R = 114
SPACE = 32
/ = 47
> = 62
*/
if l >= i+3 && ((str[i+1] == 98 || str[i+1] == 66) && (str[i+2] == 82 || str[i+2] == 114) && str[i+3] == 62) { // <br> || <BR>
buf = append(buf, bytLinefeed...)
i += 3
continue
}
if l >= i+4 && ((str[i+1] == 98 || str[i+1] == 66) && (str[i+2] == 82 || str[i+2] == 114) && str[i+3] == 47 && str[i+4] == 62) { // <br/> || <BR/>
buf = append(buf, bytLinefeed...)
i += 4
continue
}
if l >= i+5 && ((str[i+1] == 98 || str[i+1] == 66) && (str[i+2] == 82 || str[i+2] == 114) && str[i+3] == 32 && str[i+4] == 47 && str[i+5] == 62) { // <br /> || <BR />
buf = append(buf, bytLinefeed...)
i += 5
continue
}
}
default:
buf = append(buf, str[i])
}
}
return string(buf)
}
// RemoveSpace 移除字符串中的空白字符.
// all为true时移除全部空白,为false时只替换连续的空白字符为一个空格.
func RemoveSpace(str string, all bool) string {
if all && str != "" {
return strings.Join(strings.Fields(str), "")
} else if str != "" {
//先将2个以上的连续空白符转为空格
str = RegWhitespaceDuplicate.ReplaceAllString(str, " ")
//再将[\t\n\f\r]等转为空格
str = RegWhitespace.ReplaceAllString(str, " ")
}
return strings.TrimSpace(str)
}
// StripTags 过滤html标签.
func StripTags(str string) string {
return RegHtmlTag.ReplaceAllString(str, "")
}
// Html2Text 将html转换为纯文本.
func Html2Text(str string) string {
domDoc := xhtml.NewTokenizer(strings.NewReader(str))
previousStartToken := domDoc.Token()
var text string
loopDom:
for {
nx := domDoc.Next()
switch {
case nx == xhtml.ErrorToken:
break loopDom // End of the document
case nx == xhtml.StartTagToken:
previousStartToken = domDoc.Token()
case nx == xhtml.TextToken:
if chk, _ := Dstrpos(previousStartToken.Data, textHtmlExcludeTags, false); chk {
continue
}
text += " " + strings.TrimSpace(xhtml.UnescapeString(string(domDoc.Text())))
}
}
return RemoveSpace(text, false)
}
// ParseStr 将URI查询字符串转换为字典.
func ParseStr(encodedString string, result map[string]interface{}) error {
// split encodedString.
if encodedString[0] == '?' {
encodedString = strings.TrimLeft(encodedString, "?")
}
parts := strings.Split(encodedString, "&")
for _, part := range parts {
pos := strings.Index(part, "=")
if pos <= 0 {
continue
}
key, err := url.QueryUnescape(part[:pos])
if err != nil {
return err
}
for key[0] == ' ' && key[1:] != "" {
key = key[1:]
}
if key == "" || key[0] == '[' {
continue
}
value, err := url.QueryUnescape(part[pos+1:])
if err != nil {
return err
}
// split into multiple keys
var keys []string
left := 0
for i, k := range key {
if k == '[' && left == 0 {
left = i
} else if k == ']' {
if left > 0 {
if len(keys) == 0 {
keys = append(keys, key[:left])
}
keys = append(keys, key[left+1:i])
left = 0
if i+1 < len(key) && key[i+1] != '[' {
break
}
}
}
}
if len(keys) == 0 {
keys = append(keys, key)
}
// first key
first := ""
for i, chr := range keys[0] {
if chr == ' ' || chr == '.' || chr == '[' {
first += "_"
} else {
first += string(chr)
}
if chr == '[' {
first += keys[0][i+1:]
break
}
}
keys[0] = first
// build nested map
if err := BuildQueryMap(result, keys, value); err != nil {
return err
}
}
return nil
}
// ParseUrl 解析URL,返回其组成部分.
// component为需要返回的组成;
// -1: all; 1: scheme; 2: host; 4: port; 8: user; 16: pass; 32: path; 64: query; 128: fragment .
func ParseUrl(str string, component int16) (map[string]string, error) {
u, err := url.Parse(str)
if err != nil {
return nil, err
}
if component == -1 {
component = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128
}
var res = make(map[string]string)
if (component & 1) == 1 {
res["scheme"] = u.Scheme
}
if (component & 2) == 2 {
res["host"] = u.Hostname()
}
if (component & 4) == 4 {
res["port"] = u.Port()
}
if (component & 8) == 8 {
res["user"] = u.User.Username()
}
if (component & 16) == 16 {
res["pass"], _ = u.User.Password()
}
if (component & 32) == 32 {
res["path"] = u.Path
}
if (component & 64) == 64 {
res["query"] = u.RawQuery
}
if (component & 128) == 128 {
res["fragment"] = u.Fragment
}
return res, nil
}
// UrlEncode 编码 URL 字符串.
func UrlEncode(str string) string {
return url.QueryEscape(str)
}
// UrlDecode 解码已编码的 URL 字符串.
func UrlDecode(str string) (string, error) {
return url.QueryUnescape(str)
}
// RawUrlEncode 按照 RFC 3986 对 URL 进行编码.
func RawUrlEncode(str string) string {
return strings.Replace(url.QueryEscape(str), "+", "%20", -1)
}
// RawUrlDecode 对已编码的 URL 字符串进行解码.
func RawUrlDecode(str string) (string, error) {
return url.QueryUnescape(strings.Replace(str, "%20", "+", -1))
}
// HttpBuildQuery 根据参数生成 URL-encode 之后的请求字符串.
func HttpBuildQuery(queryData url.Values) string {
return queryData.Encode()
}
// FormatUrl 格式化URL.
func FormatUrl(str string) string {
if str != "" {
if Strpos(str, "://", 0) == -1 {
str = "http://" + str
}
// 将"\"替换为"/"
str = strings.ReplaceAll(str, "\\", "/")
// 将连续的"//"或"\\"或"\/",替换为"/"
str = RegUrlBackslashDuplicate.ReplaceAllString(str, "$1/")
}
return str
}
// GetDomain 从URL字符串中获取域名.
// 可选参数isMain,默认为false,取完整域名;为true时,取主域名(如abc.test.com取test.com).
func GetDomain(str string, isMain ...bool) string {
str = FormatUrl(str)
u, err := url.Parse(str)
main := false
if len(isMain) > 0 {
main = isMain[0]
}
if err != nil || !strings.Contains(str, ".") {
return ""
} else if !main {
return u.Hostname()
}
parts := strings.Split(u.Hostname(), ".")
domain := parts[len(parts)-2] + "." + parts[len(parts)-1]
return domain
}
// ClearUrlPrefix 清除URL的前缀;
// str为URL字符串,prefix为前缀,默认"/".
func ClearUrlPrefix(str string, prefix ...string) string {
var p string = "/"
if len(prefix) > 0 {
p = prefix[0]
}
for p != "" && strings.HasPrefix(str, p) {
str = str[len(p):]
}
return str
}
// ClearUrlSuffix 清除URL的后缀;
// str为URL字符串,suffix为后缀,默认"/".
func ClearUrlSuffix(str string, suffix ...string) string {
var s string = "/"
if len(suffix) > 0 {
s = suffix[0]
}
for s != "" && strings.HasSuffix(str, s) {
str = str[0 : len(str)-len(s)]
}
return str
}
// Random 生成随机字符串.
// length为长度,rtype为枚举:
// RAND_STRING_ALPHA 字母;
// RAND_STRING_NUMERIC 数值;
// RAND_STRING_ALPHANUM 字母+数值;
// RAND_STRING_SPECIAL 字母+数值+特殊字符;
// RAND_STRING_CHINESE 仅中文.
func Random(length uint8, rtype LkkRandString) string {
if length == 0 {
return ""
}
var letter []rune
alphas := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
numbers := "0123456789"
specials := "~!@#$%^&*()_+{}:|<>?`-=;,."
rand.Seed(time.Now().UTC().UnixNano())
switch rtype {
case RAND_STRING_ALPHA:
letter = []rune(alphas)
case RAND_STRING_NUMERIC:
letter = []rune(numbers)
case RAND_STRING_ALPHANUM:
letter = []rune(alphas + numbers)
case RAND_STRING_SPECIAL:
letter = []rune(alphas + numbers + specials)
case RAND_STRING_CHINESE:
letter = commonChinese
default:
letter = []rune(alphas)
}
res := make([]rune, length)
for i := range res {
res[i] = letter[rand.Intn(len(letter))]
}
return string(res)
}
// DetectEncoding 匹配字符编码,TODO.
func DetectEncoding(str string) (res string) {
//TODO 检查字符编码
return
}
// Ucfirst 将字符串的第一个字符转换为大写.
func Ucfirst(str string) string {
for _, v := range str {
u := string(unicode.ToUpper(v))
return u + str[len(u):]
}
return ""
}
// Lcfirst 将字符串的第一个字符转换为小写.
func Lcfirst(str string) string {
for _, v := range str {
u := string(unicode.ToLower(v))
return u + str[len(u):]
}
return ""
}
// Ucwords 将字符串中每个词的首字母转换为大写.
func Ucwords(str string) string {
caser := cases.Title(language.English)
return caser.String(str)
}
// Lcwords 将字符串中每个词的首字母转换为小写.
func Lcwords(str string) string {
buf := &bytes.Buffer{}
lastIsSpace := true
for _, r := range str {
if unicode.IsLetter(r) {
if lastIsSpace {
r = unicode.ToLower(r)
}
lastIsSpace = false
} else {
lastIsSpace = false
if unicode.IsSpace(r) || unicode.IsPunct(r) || unicode.IsSymbol(r) || unicode.IsMark(r) {
lastIsSpace = true
}
}
buf.WriteRune(r)
}
return buf.String()
}
// Substr 截取字符串str的子串.
// start 为起始位置.若值是负数,返回的结果将从 str 结尾处向前数第 abs(start) 个字符开始.
// length 为截取的长度.若值时负数, str 末尾处的 abs(length) 个字符将会被省略.
// start/length的绝对值必须<=原字符串长度.
func Substr(str string, start int, length ...int) string {
total := len(str)
if total == 0 {
return ""
}
var sublen, end int
max := total //最大的结束位置
if len(length) == 0 {
sublen = total
} else {
sublen = length[0]
}
if start < 0 {
start = total + start
}
if sublen < 0 {
sublen = total + sublen
if sublen > 0 {
max = sublen
}
}
if start < 0 || sublen <= 0 || start >= max {
return ""
}
end = start + sublen
if end > max {
end = max
}
return str[start:end]
}
// MbSubstr 返回(宽字符)字符串str的子串.
// start 为起始位置.若值是负数,返回的结果将从 str 结尾处向前数第 abs(start) 个字符开始.
// length 为截取的长度.若值时负数, str 末尾处的 abs(length) 个字符将会被省略.
// start/length的绝对值必须<=原字符串长度.
func MbSubstr(str string, start int, length ...int) string {
if len(str) == 0 {
return ""
}
runes := []rune(str)
total := len(runes)
var sublen, end int
max := total //最大的结束位置
if len(length) == 0 {
sublen = total
} else {
sublen = length[0]
}
if start < 0 {
start = total + start
}
if sublen < 0 {
sublen = total + sublen
if sublen > 0 {
max = sublen
}
}
if start < 0 || sublen <= 0 || start >= max {
return ""
}
end = start + sublen
if end > max {
end = max
}
return string(runes[start:end])
}
// SubstrCount 计算子串substr在字符串str中出现的次数,区分大小写.
func SubstrCount(str, substr string) int {
return strings.Count(str, substr)
}
// SubstriCount 计算子串substr在字符串str中出现的次数,忽略大小写.
func SubstriCount(str, substr string) int {
return strings.Count(strings.ToLower(str), strings.ToLower(substr))
}
// StringReverse 反转字符串.
func StringReverse(str string) string {
n := len(str)
runes := make([]rune, n)
for _, r := range str {
n--
runes[n] = r
}
return string(runes[n:])
}
// ChunkSplit 将字符串分割成小块.str为要分割的字符,chunklen为分割的尺寸,end为行尾序列符号.
func ChunkSplit(str string, chunklen uint, end string) string {
if end == "" {
return str
}
runes, erunes := []rune(str), []rune(end)
length := uint(len(runes))
if length <= 1 || length < chunklen {
return str + end
}
ns := make([]rune, 0, len(runes)+len(erunes))
var i uint
for i = 0; i < length; i += chunklen {
if i+chunklen > length {
ns = append(ns, runes[i:]...)
} else {
ns = append(ns, runes[i:i+chunklen]...)
}
ns = append(ns, erunes...)
}
return string(ns)
}
// Strlen 获取字符串长度.
func Strlen(str string) int {
return len(str)
}
// MbStrlen 获取宽字符串的长度,多字节的字符被计为 1.
func MbStrlen(str string) int {
return utf8.RuneCountInString(str)
}
// Shuffle 随机打乱字符串.
func Shuffle(str string) string {
if str == "" {
return str
}
runes := []rune(str)
index := 0
for i := len(runes) - 1; i > 0; i-- {
index = rand.Intn(i + 1)
if i != index {
runes[i], runes[index] = runes[index], runes[i]
}
}
return string(runes)
}
// Ord 将首字符转换为rune(ASCII值).
// 注意:当字符串为空时返回65533.
func Ord(char string) rune {
r, _ := utf8.DecodeRune([]byte(char))
return r
}
// Chr 返回相对应于 ASCII 所指定的单个字符.
func Chr(chr uint) string {
return string(rune(chr))
}
// Serialize 对变量进行序列化.
func Serialize(val interface{}) ([]byte, error) {
buf := bytes.Buffer{}
enc := gob.NewEncoder(&buf)
gob.Register(val)
err := enc.Encode(&val)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// UnSerialize 对字符串进行反序列化.
// 其中register注册对象,其类型必须和Serialize的一致.
func UnSerialize(data []byte, register ...interface{}) (val interface{}, err error) {
for _, v := range register {
gob.Register(v)
break
}
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
err = dec.Decode(&val)
return
}
// Quotemeta 转义元字符集,包括 . \ + * ? [ ^ ] ( $ )等.
func Quotemeta(str string) string {
var buf bytes.Buffer
for _, char := range str {
switch char {
case '.', '+', '\\', '(', '$', ')', '[', '^', ']', '*', '?':
buf.WriteRune('\\')
}
buf.WriteRune(char)
}
return buf.String()
}
// Htmlentities 将字符转换为 HTML 转义字符.
func Htmlentities(str string) string {
return html.EscapeString(str)
}
// HtmlentityDecode 将HTML实体转换为它们对应的字符.
func HtmlentityDecode(str string) string {
return html.UnescapeString(str)
}
// Crc32 计算一个字符串的 crc32 多项式.
func Crc32(str string) uint32 {
return crc32.ChecksumIEEE([]byte(str))
}
// Explode 字符串分割.delimiters为分隔符,可选,支持多个.
func Explode(str string, delimiters ...string) (res []string) {
if str == "" {
return
}
dLen := len(delimiters)
if dLen == 0 {
res = append(res, str)
} else if dLen > 1 {
var sl []string
for _, v := range delimiters {
if v != "" {
sl = append(sl, v, KDelimiter)
}
}
str = strings.NewReplacer(sl...).Replace(str)
res = strings.Split(str, KDelimiter)
} else {
res = strings.Split(str, delimiters[0])
}
return
}
// Uniqid 获取一个带前缀的唯一ID(24位).
// prefix 为前缀字符串.
func Uniqid(prefix string) string {
buf := make([]byte, 12)
_, _ = crand.Read(buf)
return fmt.Sprintf("%s%08x%16x",
prefix,
buf[0:4],
buf[4:12])
}
// UuidV4 获取36位UUID(Version4,RFC4122).
func UuidV4() (string, error) {
u := make([]byte, 16)
_, err := crand.Read(u)
//sets the version bits
u[6] = (u[6] & 0x0f) | (3 << 4)
//sets the variant bits
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
u[0:4],
u[4:6],
u[6:8],
u[8:10],
u[10:16]), err
}
// UuidV5 根据提供的字符,使用sha1生成36位哈希值(Version5,RFC4122);
// name为要计算散列值的字符,可以为nil;
// namespace为命名空间,长度必须为16.
func UuidV5(name, namespace []byte) (string, error) {
var nsSize = len(namespace)
if nsSize != 16 {
return "", fmt.Errorf("[UuidV5]`s namespace must be exactly 16 bytes long, got %d bytes", nsSize)
}
var h = sha1.New()
h.Write(namespace)
h.Write(name)
u := make([]byte, 16)
copy(u[:], h.Sum(nil))
//sets the version bits
u[6] = (u[6] & 0x0f) | (5 << 4)
//sets the variant bits
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
buf := make([]byte, 36)
hex.Encode(buf[0:8], u[0:4])
buf[8] = '-'
hex.Encode(buf[9:13], u[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], u[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], u[8:10])
buf[23] = '-'
hex.Encode(buf[24:], u[10:])
return string(buf), nil
}
// VersionCompare 对比两个版本号字符串.
// operator允许的操作符有: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne .
// 特定的版本字符串,将会用以下顺序处理:
// 无 < dev < alpha = a < beta = b < RC = rc < # < pl = p < ga < release = r
// 用法:
// VersionCompare("1.2.3-alpha", "1.2.3RC7", '>=') ;
// VersionCompare("1.2.3-beta", "1.2.3pl", 'lt') ;
// VersionCompare("1.1_dev", "1.2any", 'eq') .
func VersionCompare(version1, version2, operator string) (bool, error) {
var canonicalize func(string) string
var vcompare func(string, string) int
var special func(string, string) int
// canonicalize 规范化转换
canonicalize = func(version string) string {
ver := []byte(version)
l := len(ver)
var buf = make([]byte, l*2)
j := 0
for i, v := range ver {
next := uint8(0)
if i+1 < l { // Have the next one
next = ver[i+1]
}
if v == '-' || v == '_' || v == '+' { // replace '-', '_', '+' to '.'
if j > 0 && buf[j-1] != '.' {
buf[j] = '.'
j++
}
} else if (next > 0) &&
(!(next >= '0' && next <= '9') && (v >= '0' && v <= '9')) ||
(!(v >= '0' && v <= '9') && (next >= '0' && next <= '9')) { // Insert '.' before and after a non-digit
buf[j] = v
j++
if v != '.' && next != '.' {
buf[j] = '.'
j++
}
continue
} else if !((v >= '0' && v <= '9') ||
(v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z')) { // Non-letters and numbers
if j > 0 && buf[j-1] != '.' {
buf[j] = '.'
j++
}
} else {
buf[j] = v
j++
}
}
return string(buf[:j])
}
// version compare
// 在第一个版本低于第二个时,vcompare() 返回 -1;如果两者相等,返回 0;第二个版本更低时则返回 1.
vcompare = func(origV1, origV2 string) int {
if origV1 == "" || origV2 == "" {
if origV1 == "" && origV2 == "" {
return 0
}
if origV1 == "" {
return -1
}
return 1
}
ver1, ver2, compare := canonicalize(origV1), canonicalize(origV2), 0
n1, n2 := 0, 0
for {
p1, p2 := "", ""
n1 = strings.IndexByte(ver1, '.')
if n1 == -1 {
p1, ver1 = ver1[:], ""
} else {
p1, ver1 = ver1[:n1], ver1[n1+1:]
}
n2 = strings.IndexByte(ver2, '.')
if n2 == -1 {
p2, ver2 = ver2, ""
} else {
p2, ver2 = ver2[:n2], ver2[n2+1:]
}
if p1 == "" || p2 == "" {
break
}
if (p1[0] >= '0' && p1[0] <= '9') && (p2[0] >= '0' && p2[0] <= '9') { // all is digit
l1, _ := strconv.Atoi(p1)
l2, _ := strconv.Atoi(p2)
if l1 > l2 {
compare = 1
} else if l1 == l2 {
compare = 0
} else {
compare = -1
}
} else {
compare = special(p1, p2)
}
if compare != 0 || n1 == -1 || n2 == -1 {
break
}
}
return compare
}
// compare special version forms 特殊版本号
special = func(form1, form2 string) int {
found1, found2 := -1, -1
// (Any string not found) < dev < alpha = a < beta = b < RC = rc < # < pl = p < ga < release = r
forms := map[string]int{
"dev": 0,
"alpha": 1,
"a": 1,
"beta": 2,
"b": 2,
"RC": 3,
"rc": 3,
"#": 4,
"pl": 5,
"p": 5,
"ga": 6,
"release": 7,
"r": 7,
}
for name, order := range forms {
if form1 == name {
found1 = order
break
}
}
for name, order := range forms {
if form2 == name {
found2 = order
break
}
}
if found1 == found2 {
if found1 == -1 {
return strings.Compare(form1, form2)
}
return 0
} else if found1 > found2 {
return 1
} else {
return -1
}
}
compare := vcompare(version1, version2)
// 在第一个版本低于第二个时,vcompare() 返回 -1;如果两者相等,返回 0;第二个版本更低时则返回 1.
switch operator {
case "<", "lt":
return compare == -1, nil
case "<=", "le":
return compare != 1, nil
case ">", "gt":
return compare == 1, nil
case ">=", "ge":
return compare != -1, nil
case "==", "=", "eq":
return compare == 0, nil
case "!=", "<>", "ne":
return compare != 0, nil
default:
return false, errors.New("[VersionCompare]`operator: invalid")
}
}
// ToCamelCase 转为驼峰写法.
// 去掉包括下划线"_"和横杠"-".
func ToCamelCase(str string) string {
if len(str) == 0 {
return ""
}
buf := &bytes.Buffer{}
var r0, r1 rune
var size int
// leading connector will appear in output.
for len(str) > 0 {
r0, size = utf8.DecodeRuneInString(str)
str = str[size:]
if !isCaseConnector(r0) {
r0 = unicode.ToUpper(r0)
break
}
buf.WriteRune(r0)
}
for len(str) > 0 {
r1 = r0
r0, size = utf8.DecodeRuneInString(str)
str = str[size:]
if isCaseConnector(r0) && isCaseConnector(r1) {
buf.WriteRune(r1)
continue
}
if isCaseConnector(r1) {
r0 = unicode.ToUpper(r0)
} else if unicode.IsLower(r1) && unicode.IsUpper(r0) {
buf.WriteRune(r1)
} else if unicode.IsUpper(r1) && unicode.IsLower(r0) {
buf.WriteRune(r1)
} else {
r0 = unicode.ToLower(r0)
buf.WriteRune(r1)
}
}
buf.WriteRune(r0)
return buf.String()
}
// ToSnakeCase 转为蛇形写法.
// 使用下划线"_"连接.
func ToSnakeCase(str string) string {
return CamelCaseToLowerCase(str, '_')
}
// ToSnakeCase 转为串形写法.
// 使用横杠"-"连接.
func ToKebabCase(str string) string {
return CamelCaseToLowerCase(str, '-')
}
// RemoveBefore 移除before之前的字符串;
// include为是否移除包括before本身;
// ignoreCase为是否忽略大小写.
func RemoveBefore(str, before string, include, ignoreCase bool) string {
i := Index(str, before, ignoreCase)
if i > 0 {
if include {
str = str[i+len(before):]
} else {
str = str[i:]
}
}
return str
}
// RemoveAfter 移除after之后的字符串;
// include为是否移除包括after本身;
// ignoreCase为是否忽略大小写.
func RemoveAfter(str, after string, include, ignoreCase bool) string {
i := Index(str, after, ignoreCase)
if i > 0 {
if include {
str = str[0:i]
} else {
str = str[0 : i+len(after)]
}
}
return str
}
// DBC2SBC 半角转全角.
func DBC2SBC(s string) string {
return width.Widen.String(s)
}
// SBC2DBC 全角转半角.
func SBC2DBC(s string) string {
return width.Narrow.String(s)
}
// Levenshtein 计算两个字符串之间的编辑距离,返回值越小字符串越相似.
// 注意字符串最大长度为255.
func Levenshtein(a, b string) int {
la := len(a)
lb := len(b)
if a == b {
return 0
} else if la > 255 || lb > 255 {
return -1
}
d := make([]int, la+1)
var lastdiag, olddiag, temp int
for i := 1; i <= la; i++ {
d[i] = i
}
for i := 1; i <= lb; i++ {
d[0] = i
lastdiag = i - 1
for j := 1; j <= la; j++ {
olddiag = d[j]
min := d[j] + 1
if (d[j-1] + 1) < min {
min = d[j-1] + 1
}
if (a)[j-1] == (b)[i-1] {
temp = 0
} else {
temp = 1
}
if (lastdiag + temp) < min {
min = lastdiag + temp
}
d[j] = min
lastdiag = olddiag
}
}
return d[la]
}
// ClosestWord 获取与原字符串相似度最高的字符串,以及它们的编辑距离.
// word为原字符串,searchs为待查找的字符串数组.
func ClosestWord(word string, searchs []string) (string, int) {
distance := 10000
res := ""
for _, search := range searchs {
newVal := Levenshtein(word, search)
if newVal == 0 {
distance = 0
res = search
break
}
if newVal < distance {
distance = newVal
res = search
}
}
return res, distance
}
// Utf8ToBig5 UTF-8转BIG5编码.
func Utf8ToBig5(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), traditionalchinese.Big5.NewEncoder())
d, e := ioutil.ReadAll(reader)
return d, e
}
// Big5ToUtf8 BIG5转UTF-8编码.
func Big5ToUtf8(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), traditionalchinese.Big5.NewDecoder())
d, e := ioutil.ReadAll(reader)
return d, e
}
// FirstLetter 获取字符串首字母.
func FirstLetter(str string) string {
if str != "" {
// 获取字符串第一个字符
_, size := utf8.DecodeRuneInString(str)
firstChar := str[:size]
if IsLetters(firstChar) {
return firstChar
} else if IsChinese(firstChar) {
// Utf8 转 GBK2312
firstCharGbk, _ := Utf8ToGbk([]byte(firstChar))
// 获取第一个字符的16进制
firstCharHex := hex.EncodeToString(firstCharGbk)
// 16进制转十进制
firstCharDec, _ := strconv.ParseInt(firstCharHex, 16, 0)
// 十进制落在GB 2312的某个拼音区间即为某个字母
firstCharDecimalRelative := firstCharDec - 65536
if firstCharDecimalRelative >= -20319 && firstCharDecimalRelative <= -20284 {
return "A"
}
if firstCharDecimalRelative >= -20283 && firstCharDecimalRelative <= -19776 {
return "B"
}
if firstCharDecimalRelative >= -19775 && firstCharDecimalRelative <= -19219 {
return "C"
}
if firstCharDecimalRelative >= -19218 && firstCharDecimalRelative <= -18711 {
return "D"
}
if firstCharDecimalRelative >= -18710 && firstCharDecimalRelative <= -18527 {
return "E"
}
if firstCharDecimalRelative >= -18526 && firstCharDecimalRelative <= -18240 {
return "F"
}
if firstCharDecimalRelative >= -18239 && firstCharDecimalRelative <= -17923 {
return "G"
}
if firstCharDecimalRelative >= -17922 && firstCharDecimalRelative <= -17418 {
return "H"
}
if firstCharDecimalRelative >= -17417 && firstCharDecimalRelative <= -16475 {
return "J"
}
if firstCharDecimalRelative >= -16474 && firstCharDecimalRelative <= -16213 {
return "K"
}
if firstCharDecimalRelative >= -16212 && firstCharDecimalRelative <= -15641 {
return "L"
}
if firstCharDecimalRelative >= -15640 && firstCharDecimalRelative <= -15166 {
return "M"
}
if firstCharDecimalRelative >= -15165 && firstCharDecimalRelative <= -14923 {
return "N"
}
if firstCharDecimalRelative >= -14922 && firstCharDecimalRelative <= -14915 {
return "O"
}
if firstCharDecimalRelative >= -14914 && firstCharDecimalRelative <= -14631 {
return "P"
}
if firstCharDecimalRelative >= -14630 && firstCharDecimalRelative <= -14150 {
return "Q"
}
if firstCharDecimalRelative >= -14149 && firstCharDecimalRelative <= -14091 {
return "R"
}
if firstCharDecimalRelative >= -14090 && firstCharDecimalRelative <= -13319 {
return "S"
}
if firstCharDecimalRelative >= -13318 && firstCharDecimalRelative <= -12839 {
return "T"
}
if firstCharDecimalRelative >= -12838 && firstCharDecimalRelative <= -12557 {
return "W"
}
if firstCharDecimalRelative >= -12556 && firstCharDecimalRelative <= -11848 {
return "X"
}
if firstCharDecimalRelative >= -11847 && firstCharDecimalRelative <= -11056 {
return "Y"
}
if firstCharDecimalRelative >= -11055 && firstCharDecimalRelative <= -10247 {
return "Z"
}
}
}
return ""
}
// HideCard 隐藏证件号码.
func HideCard(card string) string {
res := "******"
leng := len(card)
if leng > 4 && leng <= 10 {
res = card[0:4] + "******"
} else if leng > 10 {
res = card[0:4] + "******" + card[(leng-4):leng]
}
return res
}
// HideMobile 隐藏手机号.
func HideMobile(mobile string) string {
res := "***"
leng := len(mobile)
if leng > 7 {
res = mobile[0:3] + "****" + mobile[leng-3:leng]
}
return res
}
// HideTrueName 隐藏真实名称(如姓名、账号、公司等).
func HideTrueName(name string) string {
res := "**"
if name != "" {
runs := []rune(name)
leng := len(runs)
if leng <= 3 {
res = string(runs[0:1]) + res
} else if leng < 5 {
res = string(runs[0:2]) + res
} else if leng < 10 {
res = string(runs[0:2]) + "***" + string(runs[leng-2:leng])
} else if leng < 16 {
res = string(runs[0:3]) + "****" + string(runs[leng-3:leng])
} else {
res = string(runs[0:4]) + "*****" + string(runs[leng-4:leng])
}
}
return res
}
// CountBase64Byte 粗略统计base64字符串大小,字节.
func CountBase64Byte(str string) (res int) {
pos := strings.Index(str, ",")
if pos > 10 {
img := strings.Replace(str[pos:], "=", "", -1)
res = int(float64(len(img)) * float64(3.0/4.0))
}
return
}
// Strpad 使用fill填充str字符串到指定长度max.
// ptype为填充类型,枚举值(PAD_LEFT,PAD_RIGHT,PAD_BOTH).
func Strpad(str string, fill string, max int, ptype LkkPadType) string {
runeStr := []rune(str)
runeStrLen := len(runeStr)
if runeStrLen >= max || max < 1 || len(fill) == 0 {
return str
}
var leftsize int
var rightsize int
switch ptype {
case PAD_BOTH:
rlsize := float64(max-runeStrLen) / 2
leftsize = int(rlsize)
rightsize = int(rlsize + math.Copysign(0.5, rlsize))
case PAD_LEFT:
leftsize = max - runeStrLen
case PAD_RIGHT:
rightsize = max - runeStrLen
}
buf := make([]rune, 0, max)
if ptype == PAD_LEFT || ptype == PAD_BOTH {
for i := 0; i < leftsize; {
for _, v := range []rune(fill) {
buf = append(buf, v)
if i >= leftsize-1 {
i = leftsize
break
} else {
i++
}
}
}
}
buf = append(buf, runeStr...)
if ptype == PAD_RIGHT || ptype == PAD_BOTH {
for i := 0; i < rightsize; {
for _, v := range []rune(fill) {
buf = append(buf, v)
if i >= rightsize-1 {
i = rightsize
break
} else {
i++
}
}
}
}
return string(buf)
}
// StrpadLeft 字符串左侧填充,请参考Strpad.
func StrpadLeft(str string, fill string, max int) string {
return Strpad(str, fill, max, PAD_LEFT)
}
// StrpadRight 字符串右侧填充,请参考Strpad.
func StrpadRight(str string, fill string, max int) string {
return Strpad(str, fill, max, PAD_RIGHT)
}
// StrpadBoth 字符串两侧填充,请参考Strpad.
func StrpadBoth(str string, fill string, max int) string {
return Strpad(str, fill, max, PAD_BOTH)
}
// CountWords 统计字符串中单词的使用情况.
// 返回结果:单词总数;和一个字典,包含每个单词的单独统计.
// 因为没有分词,对中文尚未很好支持.
func CountWords(str string) (int, map[string]int) {
//过滤标点符号
var buffer bytes.Buffer
for _, r := range str {
if unicode.IsPunct(r) || unicode.IsSymbol(r) || unicode.IsMark(r) {
buffer.WriteRune(' ')
} else {
buffer.WriteRune(r)
}
}
var total int
mp := make(map[string]int)
words := strings.Fields(buffer.String())
for _, word := range words {
mp[word] += 1
total++
}
return total, mp
}
// HasEmoji 字符串是否含有表情符.
func HasEmoji(str string) bool {
return str != "" && RegEmoji.MatchString(str)
}
// RemoveEmoji 移除字符串中的表情符(使用正则,效率较低).
func RemoveEmoji(str string) string {
return RegEmoji.ReplaceAllString(str, "")
}
// Gravatar 获取Gravatar头像地址.
// email为邮箱;size为头像尺寸像素.
func Gravatar(email string, size uint16) string {
h := md5.New()
_, _ = io.WriteString(h, email)
return fmt.Sprintf("https://www.gravatar.com/avatar/%x?s=%d", h.Sum(nil), size)
}
// AtWho 查找被@的用户名.minLen为用户名最小长度,默认5.
func AtWho(text string, minLen ...int) []string {
var result = []string{}
var username string
var min int = 5
if len(minLen) > 0 && minLen[0] > 0 {
min = minLen[0]
}
for _, line := range strings.Split(text, "\n") {
if len(line) == 0 {
continue
}
for {
index := strings.Index(line, "@")
if index == -1 {
break
} else if index > 0 {
r := rune(line[index-1])
if unicode.IsUpper(r) || unicode.IsLower(r) {
line = line[index+1:]
} else {
line = line[index:]
}
} else if index == 0 {
// the "@" is first characters
endIndex := strings.Index(line, " ")
if endIndex == -1 {
username = line[1:]
} else {
username = line[1:endIndex]
}
if len(username) >= min && RegUsernameen.MatchString(username) && !InStringSlice(username, result) {
result = append(result, username)
}
if endIndex == -1 {
break
}
line = line[endIndex:]
}
}
}
return result
}
// MatchEquations 匹配字符串中所有的等式.
func MatchEquations(str string) (res []string) {
res = RegEquation.FindAllString(str, -1)
return
}
// GetEquationValue 获取等式str中变量name的值.
func GetEquationValue(str, name string) (res string) {
pattern := `['"]?` + name + `['"]?[\s]*=[\s]*['"]?(.*)['"]?`
reg := regexp.MustCompile(pattern)
mat := reg.FindStringSubmatch(str)
if len(mat) == 2 {
res = mat[1]
}
return
}
// PasswordSafeLevel 检查密码安全等级;为0 极弱,为1 弱,为2 一般,为3 很好,为4 极佳.
func PasswordSafeLevel(str string) (res uint8) {
length := len(str)
if length > 0 {
var scoreTotal, scoreAlphaNumber, scoreSpecial int
//根据长度加分
if length >= 6 {
scoreTotal += length
} else {
scoreTotal += 1
}
var repeatMap = make(map[rune]int)
//根据类型加分
for _, char := range str {
if _, ok := repeatMap[char]; ok {
repeatMap[char] += 1
} else {
repeatMap[char] = 1
}
if !unicode.IsNumber(char) && !unicode.IsLower(char) && !unicode.IsUpper(char) { //其他(特殊)字符
if scoreSpecial == 0 {
scoreSpecial = 6
} else {
scoreSpecial += 2
}
} else {
if scoreAlphaNumber == 0 {
scoreAlphaNumber = 3
} else {
scoreTotal += 1
}
}
}
scoreTotal += scoreAlphaNumber + scoreSpecial
//重复性检查
for _, num := range repeatMap {
if num > 1 {
scoreTotal -= num * 2
}
}
if scoreTotal <= 0 { //极弱
res = 0
} else if scoreTotal <= 20 { //弱
res = 1
} else if scoreTotal <= 30 { //一般
res = 2
} else if scoreTotal <= 40 { //很好
res = 3
} else { //极佳
res = 4
}
//是否弱密码
for _, v := range weakPasswords {
if v == str || Index(str, v, true) == 0 {
res = 1
break
}
}
}
return
}
func StringFormatBigInt(mem uint64) string {
switch {
case mem >= 10e12:
return fmt.Sprintf("%dT", mem/1e12)
case mem >= 1e12:
return strings.TrimSuffix(fmt.Sprintf("%.1fT", float64(mem)/1e12), ".0")
case mem >= 10e9:
return fmt.Sprintf("%dG", mem/1e9)
case mem >= 1e9:
return strings.TrimSuffix(fmt.Sprintf("%.1fG", float64(mem)/1e9), ".0")
case mem >= 10e6:
return fmt.Sprintf("%dM", mem/1e6)
case mem >= 1e6:
return strings.TrimSuffix(fmt.Sprintf("%.1fM", float64(mem)/1e6), ".0")
case mem >= 10e3:
return fmt.Sprintf("%dk", mem/1e3)
case mem >= 1e3:
return strings.TrimSuffix(fmt.Sprintf("%.1fk", float64(mem)/1e3), ".0")
}
return fmt.Sprintf("%d", mem)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。