代码拉取完成,页面将自动刷新
package gobase
import (
"bytes"
"crypto/md5"
"encoding/binary"
"fmt"
"io"
"math"
"math/rand"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
"time"
"unicode"
"unicode/utf8"
"unsafe"
)
const (
EMPTY_STRING string = ""
QUOTECHR = '"'
)
var (
ErrUnsupported = fmt.Errorf("unsupported")
)
/*
*
字符集 字数 Unicode 编码
基本汉字 20902字 4E00-9FA5 // 一 ~ 龥 (简繁)
基本汉字补充 90字 9FA6-9FFF
扩展A 6592字 3400-4DBF
扩展B 42720字 20000-2A6DF
扩展C 4153字 2A700-2B738
扩展D 222字 2B740-2B81D
扩展E 5762字 2B820-2CEA1
扩展F 7473字 2CEB0-2EBE0
扩展G 4939字 30000-3134A
康熙部首 214字 2F00-2FD5
部首扩展 115字 2E80-2EF3
兼容汉字 477字 F900-FAD9
兼容扩展 542字 2F800-2FA1D
PUA(GBK)部件 81字 E815-E86F
部件扩展 452字 E400-E5E8
PUA增补 207字 E600-E6CF
汉字笔画 36字 31C0-31E3
汉字结构 12字 2FF0-2FFB
汉语注音 43字 3105-312F
注音扩展 22字 31A0-31BA
〇 1字 3007
*/
func IsChineseChar(c rune) bool {
return c >= 0x4E00 && c <= 0x9FA5
}
/*
*
包含中文和英文
*/
func ReplaceNonChineseChar(s string, newchr rune) string {
rs := []rune(s)
rval := make([]rune, 0, len(rs))
for _, chr := range rs {
if IsAsciiPrintChar(chr) || IsChineseChar(chr) {
rval = append(rval, chr)
} else {
rval = append(rval, newchr)
}
}
return string(rval)
}
/*
*
包含中文和英文
*/
func DelNonChineseChar(s string) string {
rs := []rune(s)
rval := make([]rune, 0, len(rs))
for _, chr := range rs {
if IsAsciiPrintChar(chr) || IsChineseChar(chr) {
rval = append(rval, chr)
}
}
return string(rval)
}
func DelNonChineseCharEx(s string, splitchar rune) string {
idx := 0
rs := []rune(s)
rval := make([]rune, 0, len(rs))
for _, chr := range rs {
if IsAsciiPrintChar(chr) || IsChineseChar(chr) {
rval = append(rval, chr)
idx++
} else {
if idx > 0 {
rval = append(rval, splitchar)
idx = 0
}
}
}
return string(rval)
}
func ReplaceNonAsciiChar(s []byte, newchr byte) string {
rval := make([]byte, 0, len(s))
for _, chr := range s {
if IsAsciiPrintByte(chr) {
rval = append(rval, chr)
} else {
rval = append(rval, newchr)
}
}
return string(rval)
}
func DelNonAsciiChar(s []byte) string {
rval := make([]byte, 0, len(s))
for _, chr := range s {
if IsAsciiPrintByte(chr) {
rval = append(rval, chr)
}
}
return string(rval)
}
func JoinIfNoEmpty(chk string, sep string, args ...string) string {
if len(chk) == 0 {
return ""
} else {
return strings.Join(args, sep)
}
}
func DelNonAsciiCharEx(s []byte, splitchar byte) string {
idx := 0
rval := make([]byte, 0, len(s))
for _, chr := range s {
if IsAsciiPrintByte(chr) {
rval = append(rval, chr)
idx++
} else {
if idx > 0 {
rval = append(rval, splitchar)
idx = 0
}
}
}
return string(rval)
}
/*
FormatFloatVlst
*/
func FormatFloatVlst(fmtstr string, singalw int, totalwidth int, args ...float64) string {
strBuf := make([]byte, 0, len(args)*singalw)
for _, v := range args {
s0 := AddPrefixForWidth(fmt.Sprintf(fmtstr, v), singalw, " ")
strBuf = append(strBuf, []byte(s0)...)
}
s1 := string(strBuf)
if totalwidth > 0 {
s1 = AddSuffixForWidth(s1, totalwidth, " ")
}
return s1
}
func ReplaceNonPrintChar(s string, newchr rune) string {
strs := []rune(s)
rval := make([]rune, 0, len(strs))
for _, chr := range strs {
if unicode.IsPrint(chr) || (chr == 10 || chr == 13 || chr == '\t') {
rval = append(rval, chr)
} else {
rval = append(rval, newchr)
}
}
return string(rval)
}
func DelNonPrintChar(s string) string {
strs := []rune(s)
rval := make([]rune, 0, len(strs))
for _, chr := range strs {
if unicode.IsPrint(chr) || (chr == 10 || chr == 13 || chr == '\t') {
rval = append(rval, chr)
}
}
return string(rval)
}
func MD5(str string) string {
w := md5.New()
io.WriteString(w, str)
md5Buf := w.Sum(nil)
md5str := fmt.Sprintf("%x", md5Buf)
return md5str
}
func HashStr(str string) int64 {
var sum int64 = 0
for i := 0; i < len(str); i++ {
sum += int64(str[i])
}
return sum
}
func MD5Buf(data []byte) string {
w := md5.New()
w.Write(data)
md5str := fmt.Sprintf("%x", w.Sum(nil))
return md5str
}
// 如果是简单类型请不要使用该函数
// 可以使用GetStrValue函数代替
func ObjectHexAddr(v interface{}) string {
return fmt.Sprintf("%p", v)
}
/*
*
StrToNumSuffix("100K", 1024)
OK:
1M, 100K, 1G, 15
FAIL:
1KB, 1.4K 100m15k
*/
func StrToNumSuffix(str string, mult int64) int64 {
num := int64(1)
if len(str) > 1 {
switch str[len(str)-1] {
case 'G', 'g':
num *= mult
fallthrough
case 'M', 'm':
num *= mult
fallthrough
case 'K', 'k':
num *= mult
str = str[0 : len(str)-1]
}
}
parsed, _ := strconv.Atoi(str)
return int64(parsed) * num
}
/*
**
HumanSizeToSize("1024KB")
*/
func HumanSizeStrToSize(str string) int64 {
if len(str) == 0 {
return 0
}
num, suffix := SplitNumericAndRemain(str)
suffix = Trim(suffix)
suffix = strings.ToUpper(suffix)
if suffix == "KB" || suffix == "K" {
return int64(StrToFloat64Def(num, 0) * 1024)
}
if suffix == "MB" || suffix == "M" {
return int64(StrToFloat64Def(num, 0) * float64(SIZE_MB))
}
if suffix == "GB" || suffix == "G" {
return int64(StrToFloat64Def(num, 0) * float64(SIZE_GB))
}
if suffix == "TB" || suffix == "T" {
return int64(StrToFloat64Def(num, 0) * float64(SIZE_TB))
}
return 0
}
/*
**
00:00-07:00,08:00-10:00,11:00-12:00
*/
func IsInMultiSection(exp, s string) string {
itms := strings.Split(exp, ",")
if len(itms) == 1 {
itms = strings.Split(exp, ";")
}
if len(itms) == 1 {
itms = strings.Split(exp, " ")
}
for i := 0; i < len(itms); i++ {
if IsInSection(itms[i], s) {
return itms[i]
}
}
return ""
}
/*
**
00:00-07:00
*/
func IsInSection(exp, s string) bool {
exp = Trim(exp)
if len(exp) == 0 {
return false
}
itms := strings.SplitN(exp, "-", 2)
if len(itms) == 1 {
itms = strings.SplitN(exp, "~", 2)
}
if len(itms) == 1 {
return false
}
return s >= itms[0] && s <= itms[1]
}
func LastChrCnt(s string, c byte) int {
r := 0
for i := len(s) - 1; i >= 0; i-- {
if s[i] == c {
r++
} else {
return r
}
}
return r
}
// Copy From DxValue.Record
func UnEscapeJSONStr(bvalue []byte) []byte {
buf := make([]byte, 0, 256)
blen := len(bvalue)
i := 0
unicodeidx := 0
escapeType := uint8(0) //0 normal,1 json\escapin,2 unicode escape, 3 % url escape
for i < blen {
switch escapeType {
case 1: //json escapin
escapeType = 0
switch bvalue[i] {
case 'a':
buf = append(buf, '\a')
case 'b':
buf = append(buf, '\b')
case 'f':
buf = append(buf, '\f')
case 'n':
buf = append(buf, '\n')
case 'r':
buf = append(buf, '\r')
case 't':
buf = append(buf, '\t')
case 'v':
buf = append(buf, '\v')
case '\\':
buf = append(buf, '\\')
case '"':
buf = append(buf, '"')
case '\'':
buf = append(buf, '\'')
case '/':
buf = append(buf, '/')
case 'u':
escapeType = 2 // unicode decode
unicodeidx = i
default:
buf = append(buf, '\\', bvalue[i])
}
case 2: //unicode decode
if (bvalue[i] >= '0' && bvalue[i] <= '9' || bvalue[i] >= 'a' && bvalue[i] <= 'f' ||
bvalue[i] >= 'A' && bvalue[i] <= 'F') && i-unicodeidx <= 4 {
//还是正常的Unicode字符,4个字符为一组
//escapeType = 2
} else {
unicodestr := FastByte2String(bvalue[unicodeidx+1 : i])
if arune, err := strconv.ParseInt(unicodestr, 16, 32); err == nil {
l := len(buf)
buf = append(buf, 0, 0, 0, 0)
runelen := utf8.EncodeRune(buf[l:l+4], rune(arune))
buf = buf[:l+runelen]
} else {
buf = append(buf, bvalue[unicodeidx:i]...)
}
escapeType = 0
continue
}
case 3: //url escape
for j := 0; j < 3; j++ {
if (bvalue[j+i] >= '0' && bvalue[j+i] <= '9' || bvalue[i+j] >= 'a' && bvalue[i+j] <= 'f' ||
bvalue[j+i] >= 'A' && bvalue[j+i] <= 'F') && j < 2 {
//还是正常的Byte字符,2个字符为一组
//escapeType = 2
} else {
bytestr := FastByte2String(bvalue[i : i+j])
if abyte, err := strconv.ParseInt(bytestr, 16, 32); err == nil {
buf = append(buf, byte(abyte))
} else {
buf = append(buf, bvalue[i-1:i+j]...) //%要加上
}
escapeType = 0
i += j - 1
break
}
}
default: //normal
switch bvalue[i] {
case '\\':
escapeType = 1 //json escapin
case '%':
escapeType = 3 // url escape
default:
buf = append(buf, bvalue[i])
}
}
i++
}
switch escapeType {
case 1:
buf = append(buf, '\\')
case 2:
unicodestr := FastByte2String(bvalue[unicodeidx+1 : i])
if arune, err := strconv.ParseInt(unicodestr, 16, 32); err == nil {
l := len(buf)
buf = append(buf, 0, 0, 0, 0)
runelen := utf8.EncodeRune(buf[l:l+4], rune(arune))
buf = buf[:l+runelen]
} else {
buf = append(buf, bvalue[unicodeidx:i]...)
}
}
return buf
}
func CheckAllStrsIsNotEmpty(strs ...string) bool {
for i := 0; i < len(strs); i++ {
if len(strs[i]) == 0 {
return false
}
}
return true
}
// 解码转义字符,将"\u6821\u56ed\u7f51\t02%20得闲"这类字符串,解码成正常显示的字符串
func ParserJsonEscapeStr(escapedstr string) string {
return FastByte2String(UnEscapeJSONStr([]byte(escapedstr)))
}
func EscapeSQLStr(str string) string {
var buf bytes.Buffer
for _, runedata := range str {
switch runedata {
case '\'':
buf.WriteByte('\'')
buf.WriteByte('\'')
case '\\':
buf.WriteByte('\\')
buf.WriteByte('\\')
default:
buf.WriteRune(runedata)
}
}
return FastByte2String(buf.Bytes())
}
func EscapeStr4Line(str string) string {
var buf bytes.Buffer
for _, runedata := range str {
switch runedata {
case '\r':
buf.WriteByte('\\')
buf.WriteByte('r')
case '\n':
buf.WriteByte('\\')
buf.WriteByte('n')
default:
buf.WriteRune(runedata)
}
}
dataBuf := buf.Bytes()
return *(*string)(unsafe.Pointer(&dataBuf))
}
func UnEscapeStr4Line(str string) string {
var buf bytes.Buffer
var escapeflag int8 = 0
for _, chr := range []byte(str) {
switch escapeflag {
case 1:
escapeflag = 0
switch chr {
case 'r':
buf.WriteByte('\r')
case 'n':
buf.WriteByte('\n')
case 't':
buf.WriteByte('\t')
case 'a':
buf.WriteByte('\a')
case 'b':
buf.WriteByte('\b')
case 'f':
buf.WriteByte('\f')
case 'v':
buf.WriteByte('\v')
case '\\':
buf.WriteByte('\\')
case '"':
buf.WriteByte('"')
case '\'':
buf.WriteByte('\'')
case '/':
buf.WriteByte('/')
default:
buf.WriteByte(chr)
}
default: //normal
switch chr {
case '\\':
escapeflag = 1 //
default:
buf.WriteByte(chr)
}
}
}
dataBuf := buf.Bytes()
return string(dataBuf)
}
func EscapeJsonStrSimple(str string) string {
var buf bytes.Buffer
for _, runedata := range str {
switch runedata {
case '\t':
buf.WriteByte('\\')
buf.WriteByte('t')
case '\f':
buf.WriteByte('\\')
buf.WriteByte('f')
case '\r':
buf.WriteByte('\\')
buf.WriteByte('r')
case '\n':
buf.WriteByte('\\')
buf.WriteByte('n')
case '\\':
buf.WriteByte('\\')
buf.WriteByte('\\')
case '"':
buf.WriteByte('\\')
buf.WriteByte('"')
case '\b':
buf.WriteByte('\\')
buf.WriteByte('b')
default:
buf.WriteRune(runedata)
}
}
return FastByte2String(buf.Bytes())
}
// Copy From DxValue.Record
func EscapeJsonStr(str string) string {
var buf bytes.Buffer
for _, runedata := range str {
switch runedata {
case '\t':
buf.WriteByte('\\')
buf.WriteByte('t')
case '\f':
buf.WriteByte('\\')
buf.WriteByte('f')
case '\r':
buf.WriteByte('\\')
buf.WriteByte('r')
case '\n':
buf.WriteByte('\\')
buf.WriteByte('n')
case '\\':
buf.WriteByte('\\')
buf.WriteByte('\\')
case '"':
buf.WriteByte('\\')
buf.WriteByte('"')
case '\b':
buf.WriteByte('\\')
buf.WriteByte('b')
default:
if runedata < 256 {
buf.WriteByte(byte(runedata))
} else {
buf.Write([]byte{'\\', 'u'})
var b [4]byte
binary.BigEndian.PutUint32(b[:], uint32(runedata))
if b[0] == 0 && b[1] == 0 {
hexstr := Binary2Hex(b[2:])
buf.WriteString(hexstr)
} else {
hexstr := Binary2Hex(b[0:2])
buf.WriteString(hexstr)
buf.Write([]byte{'\\', 'u'})
hexstr = Binary2Hex(b[2:])
buf.WriteString(hexstr)
}
}
}
}
return FastByte2String(buf.Bytes())
}
// 2进制转到16进制
func Binary2Hex(bt []byte) string {
var bf bytes.Buffer
vhex := [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}
for _, vb := range bt {
bf.WriteByte(vhex[vb>>4])
bf.WriteByte(vhex[vb&0xF])
}
return FastByte2String(bf.Bytes())
}
func FastByte2String(bt []byte) string {
return *(*string)(unsafe.Pointer(&bt))
}
func BufStart(buf []byte, start, l int) []byte {
return buf[start : start+l]
}
func BufToHexStr(buf []byte, l int, spliterstr string) string {
rval := ""
i := 0
for _, v := range buf {
if (l > 0) && (i >= l) {
break
}
rval = fmt.Sprintf("%s%.2X%s", rval, v, spliterstr)
i++
}
return rval
}
/*
*
RangeStringSplit("a\r\n汉字b\r\n", "\r\n", func)
*/
func RangeStringSplit(s string, sep string, cb func(idx int, s string) bool) int {
if len(sep) == 0 {
cb(0, s)
return 1
}
i := 0
idx := 0
for {
n := strings.Index(s[i:], sep)
if n == -1 {
cb(idx, s[i:])
idx++
break
} else {
ok := cb(idx, s[i:i+n])
idx++
i += n + len(sep)
if !ok || i >= len(s) {
break
}
}
}
return idx
}
/*
**
RangeStringSep("a01;a02", ';', fn); // 2次
RangeStringSep("a01", ';', fn); // 1次
RangeStringSep("a01;", ';', fn); // 1次
RangeStringSep("a01;;", ';', fn); // 2次
*/
func RangeStringSep(s string, sep rune, cb func(idx int, s1 string) bool) int {
s1 := []rune(s)
j := 0
n := 0
i := 0
var ok = true
for ; i < len(s1); i++ {
if s1[i] == sep {
ok = cb(n, string(s1[j:i]))
n++
if !ok {
break
}
j = i + 1
}
}
if ok {
if j < len(s1) {
cb(n, string(s1[j:]))
n++
}
}
return n
}
/*
**
RangeStringSep2("a01;a02", fn, ';', ',');
*/
func RangeStringSep2(s string, cb func(idx int, s1 string) bool, sep0, sep1 rune) int {
s1 := []rune(s)
j := 0
n := 0
i := 0
var ok bool
for ; i < len(s1); i++ {
if s1[i] == sep0 || s1[i] == sep1 {
ok = cb(n, string(s1[j:i]))
n++
if !ok {
break
}
j = i + 1
}
}
if ok {
if j < len(s1) {
cb(n, string(s1[j:]))
n++
}
}
return n
}
func RangeByteFromHexStr(hexstr string, cb func(v byte) bool) int {
hexstr = strings.Replace(hexstr, " ", "", -1)
hexstr = strings.Replace(hexstr, "\r", "", -1)
hexstr = strings.Replace(hexstr, "\n", "", -1)
hexstrArr := []rune(hexstr)
l := len(hexstrArr)
i := 0
for {
if (i + 1) >= l {
break
}
if IsHexChar(hexstrArr[i]) && IsHexChar(hexstrArr[i+1]) {
v := byte(HexValue(hexstrArr[i])<<4 + HexValue(hexstrArr[i+1]))
i += 2
if !cb(v) {
break
}
} else {
break
}
}
return i / 2
}
func HexStrToBuf(hexstr string) []byte {
hexstr = strings.Replace(hexstr, " ", "", -1)
hexstr = strings.Replace(hexstr, "\t", "", -1)
hexstr = strings.Replace(hexstr, "\r", "", -1)
hexstr = strings.Replace(hexstr, "\n", "", -1)
hexstrArr := []rune(hexstr)
l := len(hexstrArr)
l2 := l >> 1
rval := make([]byte, 0, l2)
i := 0
for {
if (i + 1) >= l {
break
}
if IsHexChar(hexstrArr[i]) && IsHexChar(hexstrArr[i+1]) {
v := HexValue(hexstrArr[i])<<4 + HexValue(hexstrArr[i+1])
i += 2
rval = append(rval, byte(v))
} else {
break
}
}
return rval
}
func HexValue(chr rune) int {
c := int(chr)
if (c >= '0') && (c <= '9') {
return c - '0'
} else if c >= 'a' && c <= 'f' {
return 10 + c - 'a'
} else {
return 10 + c - 'A'
}
}
func HexToInt(hex string) int {
r := 0
for _, char := range []rune(hex) {
r = r<<4 + HexValue(char)
}
return r
}
/*
ASCII可显示字符
*/
func IsAsciiPrintByte(c byte) bool {
return (c >= 32 && c <= 126) || // // 32: (Space), 126:~
(c == 10 || c == 13 || c == '\t')
}
func IsAsciiPrintChar(chr rune) bool {
c := byte(chr)
return (c >= 32 && c <= 126) || // // 32: (Space), 126:~
(c == 10 || c == 13 || c == '\t')
}
func IsHexChar(chr rune) bool {
c := byte(chr)
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')
}
func Trim(s string) string {
return strings.Trim(s, " \r\n\t")
}
func CombineIfFirstNotEmpty(s1, s2 string) string {
if len(s1) > 0 {
return s1 + s2
} else {
return s1
}
}
func CombineIfNotEmpty(s1, s2 string) string {
if len(s2) > 0 && len(s1) > 0 {
return s1 + s2
} else {
return ""
}
}
/*
*
CutIfMore(txt, 10, "..."))
*/
func CutIfMore(s string, n int, moreflagstr string) string {
strBuf := []rune(s)
if len(strBuf) < n {
return s
}
s1 := string(strBuf[:n]) + moreflagstr
return s1
}
func LeftStr(s string, n int) string {
strBuf := []rune(s)
if len(strBuf) < n {
n = len(strBuf)
}
s1 := string(strBuf[:n])
return s1
}
func CutLeft(s string, n int) (cut string, remain string) {
strBuf := []rune(s)
if len(strBuf) < n {
n = len(strBuf)
}
cut = string(strBuf[:n])
if len(strBuf) > n {
remain = string(strBuf[n:])
}
return
}
/*
*
The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
*/
func CompareIgnoreCase(s1, s2 string) int {
s1 = strings.ToLower(s1)
s2 = strings.ToLower(s2)
return strings.Compare(s1, s2)
}
/*
**
idx 从0开始
"/", "中国/人民", CutPrefixByRune("/中国/人民", 0, 1, "/")
"/中国/", "人民", CutPrefixByRune("/中国/人民", 1, 1, "/")
*/
func CutPrefixByRune(s string, idx int, cutflag byte, c rune) (cut string, remain string) {
return CutNPrefixFunc(s, idx, cutflag, func(c1 rune) bool {
return c1 == c
})
}
/*
**
idx 从0开始
"/人民", "/中国", CutSuffixByRune("/中国/人民", 0, 1, "/")
"/中国/人民", "", CutSuffixByRune("/中国/人民", 1, 1, "/")
*/
func CutSuffixByRune(s string, idx int, cutflag byte, c rune) (cut string, remain string) {
return CutNSuffixFunc(s, idx, cutflag, func(c1 rune) bool {
return c1 == c
})
}
func CutNPrefixFunc(s string, idx int, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
i := 0
return CutPrefixFunc(s, cutflag, func(c rune) bool {
if CheckCutBreakFunc(c) {
if i == idx {
return true
} else {
i++
return false
}
} else {
return false
}
})
}
func CutNSuffixFunc(s string, idx int, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
i := 0
return CutSuffixFunc(s, cutflag, func(c rune) bool {
if CheckCutBreakFunc(c) {
if i == idx {
return true
} else {
i++
return false
}
} else {
return false
}
})
}
/*
*
如果CheckCutBreakFunc 一直为false, cut则返回"", remain则返回源字符串
返回true表示从该字符进行截断
cutflag 0: "中国/人","民"
cutflag 1: "中国/人民",""
str := "中国/人民";
plug, remain := CutPrefixFunc(str, 0, func(c rune) bool {
if c == '民'{
return true;
}
return false;
})
cutflag 0: "中国","/人民"
cutflag 1: "中国","/人民"
str := "中国/人民";
plug, remain := CutPrefixFunc(str, 0, func(c rune) bool {
if c == '/'{
return true;
}
return false;
})
fmt.Println(CutPrefixFunc("../abc.txt", 1, func(c rune) bool {
if c == '.' || c=='/'{
return false;
}
return true;
}))
../, abc.txt
*/
func CutPrefixFunc(s string, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
strBuf := []rune(s)
n := len(strBuf)
breakn := 0
cutlist := make([]rune, 0, n)
for i := 0; i < n; i++ {
c := strBuf[i]
if CheckCutBreakFunc(c) {
if cutflag == 1 {
cutlist = append(cutlist, c)
breakn = i + 1
} else {
breakn = i
}
break
} else {
cutlist = append(cutlist, c)
}
}
if breakn == 0 {
return "", s
}
return string(cutlist), string(strBuf[breakn:])
}
/*
**
如果CheckCutBreakFunc 一直为false, cut则返回"", remain则返回源字符串
*/
func CutSuffixFunc(s string, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
strBuf := []rune(s)
n := len(strBuf)
breakn := n - 1
for i := n - 1; i >= 0; i-- {
c := strBuf[i]
if CheckCutBreakFunc(c) {
if cutflag == 0 {
breakn = i + 1
} else {
breakn = i
}
break
}
}
if breakn == n-1 {
return "", s
}
return string(strBuf[breakn:]), string(strBuf[:breakn])
}
var num2char string = "0123456789ABCDEF"
func CheckTrimPrefix(s, prefix string) (bool, string) {
if len(prefix) == 0 {
return true, s
}
if !strings.HasPrefix(s, prefix) {
return false, s
}
return true, s[len(prefix):]
}
func CheckTrimSuffix(s, suffix string) (bool, string) {
if len(suffix) == 0 {
return true, s
}
if !strings.HasSuffix(s, suffix) {
return false, s
}
return true, s[:len(s)-len(suffix)]
}
func CheckAddPrefix(s, prefix string) (added bool, rval string) {
if strings.HasPrefix(s, prefix) {
return false, s
}
return true, prefix + s
}
func CheckAddSuffix(s, suffix string) (added bool, rval string) {
if strings.HasSuffix(s, suffix) {
return false, s
}
return true, s + suffix
}
func CheckAddQuoteChr(s string, prefix, suffix rune) string {
runelst := []rune(s)
l := len(runelst)
if l >= 2 && runelst[0] == prefix || runelst[l-1] == suffix {
return s
}
newlst := make([]rune, 0, l+2)
newlst = append(newlst, prefix)
newlst = append(newlst, runelst...)
newlst = append(newlst, suffix)
return string(newlst)
}
func Str2lst(s string, sep string, itmprefix, itmsuffix rune, tolower, emptyignore bool) []string {
if len(s) == 0 {
return nil
}
lst := strings.Split(s, sep)
if itmprefix == 0 && itmsuffix == 0 && !tolower && !emptyignore {
return lst
}
for i := 0; i < len(lst); i++ {
s := Trim(lst[i])
if len(s) == 0 && emptyignore {
continue
}
if tolower {
s = strings.ToLower(s)
}
if itmprefix != 0 && itmsuffix != 0 {
s = CheckAddQuoteChr(s, itmprefix, itmsuffix)
}
lst[i] = s
}
return lst
}
/*
*
截掉前后字符
*/
func CheckTrimQuoteChr(s string, prefix, suffix byte) (bool, string) {
l := len(s)
if l <= 2 || s[0] != prefix || s[l-1] != suffix {
return false, s
}
return true, s[1 : l-1]
}
/*
*
截掉前后字符串
*/
func CheckTrimQuoteString(s string, prefix, suffix string) (bool, string) {
l := len(s)
if l <= len(prefix)+len(suffix) || s[0:len(prefix)] != prefix || s[l-len(suffix):] != suffix {
return false, s
}
return true, s[len(prefix) : l-len(suffix)]
}
func init() {
rand.Seed(time.Now().UnixNano())
}
var (
// 使用下面的r, 并发会有异常
// r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
hex_strs = "0123456789ABCDEF"
key_strs = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
pass_0_strs = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
num_strs = "0123456789"
num2_strs = "012356789"
)
// 60个纤程同时进行测试没有异常
func RandHexString(len int) string {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
b := rand.Intn(16)
bytes[i] = byte(hex_strs[b])
}
return string(bytes)
}
func RandFloat64(f float64) float64 {
return f * float64(rand.Intn(100)) / 100.00
}
/*
*
比较耗cpu
*/
func RandBuf(len int) []byte {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
b := rand.Intn(255)
bytes[i] = byte(b)
}
return bytes
}
func RandNumString(len int) string {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
b := rand.Intn(9)
bytes[i] = byte(num_strs[b])
}
return string(bytes)
}
func RandNumStringWithout4(len int) string {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
b := rand.Intn(8)
bytes[i] = byte(num2_strs[b])
}
return string(bytes)
}
func StrNextSerialNo(str string, maxl int, inc int) string {
strn := GetLastNumStr(str, maxl)
if len(strn) == 0 {
return str + fmt.Sprintf("%.2d", inc)
}
strprefix := str[:len(str)-len(strn)]
fmtstr := "%." + fmt.Sprintf("%d", len(strn)) + "d"
nextv, err := strconv.ParseInt(strn, 10, 32)
if err != nil {
nextv = int64(inc)
} else {
nextv += int64(inc)
}
strn = fmt.Sprintf(fmtstr, nextv)
strv := strprefix + strn
return strv
}
func GetLastNumStr(str string, maxl int) string {
rval := ""
j := 0
for i := len(str) - 1; i >= 0; i-- {
if str[i] >= '0' && str[i] <= '9' {
rval = string(str[i]) + rval
j++
if j >= maxl {
break
}
} else {
break
}
}
return rval
}
// 60个纤程同时进行测试没有异常
func RandKeyString(len int) string {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
b := rand.Intn(37 - 1)
bytes[i] = byte(key_strs[b])
}
return string(bytes)
}
func RandPass0String(len int) string {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
b := rand.Intn(62 - 1)
bytes[i] = byte(pass_0_strs[b])
}
return string(bytes)
}
// inttohex
// DecimalToAny(113, 16, 2) = 71
func DecimalToAny(num, n, count int) string {
new_num_str := ""
var remainder int
var remainder_string string
for num != 0 {
remainder = num % n
remainder_string = string(num2char[remainder])
new_num_str = remainder_string + new_num_str //注意顺序
num = num / n
}
length := len(new_num_str)
if length == count {
return new_num_str
}
if length < count { //如果小于8位
for i := 1; i <= count-length; i++ {
new_num_str = "0" + new_num_str
}
return new_num_str
} else {
return "ERROR"
}
}
func AddSuffixForWidth(src string, width int, suffix string) string {
disl := width - len(src)
if disl < 0 {
return src
}
fixl := len(suffix)
if fixl == 0 {
suffix = " "
fixl = 1
}
if fixl == 1 {
rep := bytes.Repeat([]byte(suffix), disl)
str := src + string(rep)
return str
} else {
l := int(math.Ceil(float64(disl) / float64(fixl)))
rep := bytes.Repeat([]byte(suffix), l)
str := src + string(rep[:disl])
return str
}
}
func AddPrefixForWidth(src string, width int, prefix string) string {
disl := width - len(src)
if disl <= 0 {
return src
}
fixl := len(prefix)
if fixl == 0 {
prefix = " "
fixl = 1
}
if fixl == 1 {
rep := bytes.Repeat([]byte(prefix), disl)
str := string(rep) + src
return str
} else {
l := int(math.Ceil(float64(disl) / float64(fixl)))
rep := bytes.Repeat([]byte(prefix), l)
str := string(rep[:disl]) + src
return str
}
}
func Split2StrV1(s string, sep byte) (s1, s2 string) {
if len(s) == 0 {
return
}
idx := bytes.IndexByte([]byte(s), sep)
if idx == -1 {
s1 = s
return
}
s1 = s[:idx]
s2 = s[idx+1:]
return
}
func Split2Str(s, sep string) (s1, s2 string) {
if len(s) == 0 {
return
}
strs := strings.SplitN(s, sep, 2)
s1 = strs[0]
if len(strs) > 1 {
s2 = strs[1]
}
return
}
func Split3Str(s, sep string) (s1, s2, s3 string) {
if len(s) == 0 {
return
}
strs := strings.SplitN(s, sep, 3)
s1 = strs[0]
if len(strs) > 1 {
s2 = strs[1]
}
if len(strs) > 2 {
s3 = strs[2]
}
return
}
func SplitNumericAndRemain(str string) (numstr, remain string) {
if len(str) == 0 {
return
}
dotn := 0
numstr, remain = CutPrefixFunc(str, 0, func(c rune) bool {
if c >= '0' && c <= '9' {
return false
}
if c == '.' {
dotn++
if dotn == 1 {
return false
}
}
return true
})
return
}
func StrToFloat32Def(s string, defval float32) float32 {
v, err := strconv.ParseFloat(s, 32)
if err != nil {
return defval
} else {
return float32(v)
}
}
func StrToFloat64Def(s string, defval float64) float64 {
v, err := strconv.ParseFloat(s, 64)
if err != nil {
return defval
} else {
return float64(v)
}
}
/*
**
1 = "1"
0.1 = "0.1"
*/
func Float64ToStr(val float64) string {
str := strconv.FormatFloat(val, 'f', -1, 64)
return str
}
func Float32ToStr(val float64) string {
str := strconv.FormatFloat(val, 'f', -1, 32)
return str
}
func IsAsciiPrintStr(src string) bool {
strArr := []rune(src)
l := len(strArr)
for i := 0; i < l; i++ {
if !IsAsciiPrintChar(strArr[i]) {
return false
}
}
return true
}
func CheckGetStrlist(strs []string, idx int, def string) string {
if len(strs) > idx {
return strs[idx]
} else {
return def
}
}
func CheckGetValInlst(lst []interface{}, idx int, def interface{}) interface{} {
if len(lst) > idx {
return lst[idx]
} else {
return def
}
}
func IsPrintStr(src string) bool {
strArr := []rune(src)
l := len(strArr)
for i := 0; i < l; i++ {
chr := strArr[i]
if IsAsciiPrintChar(chr) || chr == 10 || strArr[i] == 13 || strArr[i] == '\t' {
continue
} else {
return false
}
}
return true
}
/*
*
0:无BOM
1:UTF8
*/
func DetectBOMType(data []byte) int {
if len(data) >= 3 {
if data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF {
return 1
}
}
return 0
}
/*
*
GB2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;
GBK共收入21886个汉字和图形符号。
GBK: 8140至FEFE
*/
func HaveAnyGBK(data []byte) bool {
length := len(data)
var i int = 0
for i < length {
if data[i] <= 0x7f { // 编码0~127,只有一个字节的编码,兼容ASCII码
i++
continue
} else {
//大于127的使用双字节编码,落在gbk编码范围内的字符
if i+1 < length && (data[i] >= 0x81 && data[i+1] >= 0x40 && data[i] <= 0xfe && data[i+1] <= 0xfe && data[i+1] != 0xf7) {
i += 2
return true
} else { // 非GBK
continue
// return false
}
}
}
return false
}
/*
*
src 长度必须是2的倍数, 必须都是HEX字符, 不能包含空格
*/
func IsHexStr(src string) bool {
strArr := []rune(src)
l := len(strArr)
if l%2 != 0 {
return false
}
for i := 0; i < l; i++ {
if !IsHexChar(strArr[i]) {
return false
}
}
return true
}
func StringsRangeFunc(strs []string, cb func(idx int64, elestr string) bool) (int64, error) {
index := int64(0)
for i := 0; i < len(strs); i++ {
if !cb(int64(i), strs[i]) {
break
}
index++
}
return index, nil
}
/*
**
删除符合条件的元素
*/
func DeleteStrlstEle(strs []string, fn func(s string) bool) []string {
for i := len(strs) - 1; i >= 0; i-- {
if fn(strs[i]) {
strs = append(strs[:i], strs[i+1:]...)
}
}
return strs
}
func StrIndex(s string, strlst ...string) int {
for i := 0; i < len(strlst); i++ {
if s == strlst[i] {
return i
}
}
return -1
}
func StrIndexIgnoreCase(s string, strlst ...string) int {
for i := 0; i < len(strlst); i++ {
if strings.ToLower(s) == strings.ToLower(strlst[i]) {
return i
}
}
return -1
}
/*
*
1个月 1, 个月
1 天 1,天
*/
func SplitQuantifiersUnits(s string) (qua string, unit string) {
runelst := []rune(Trim(s))
for i := 0; i < len(runelst); i++ {
chr := runelst[i]
if chr >= '0' && chr <= '9' {
continue
} else if chr == '-' || chr == '+' {
continue
} else if chr == '.' {
continue
}
if chr == ' ' || chr == '\t' || chr == '\n' {
qua = string(runelst[:i])
unit = string(runelst[i+1:])
break
} else {
qua = string(runelst[:i])
unit = string(runelst[i:])
break
}
}
return
}
func StrTo3Float64(str string, sep string) (f1, f2, f3 float64) {
strs := strings.SplitN(str, sep, 4)
if len(strs) >= 1 {
f1 = StrToFloat64Def(Trim(strs[0]), 0)
if len(strs) >= 2 {
f2 = StrToFloat64Def(Trim(strs[1]), 0)
if len(strs) >= 3 {
f3 = StrToFloat64Def(Trim(strs[2]), 0)
}
}
}
return
}
func StrToInts(str string, sep string) (rval []int) {
strs := strings.Split(str, sep)
rval = make([]int, 0, len(strs))
for i := 0; i < len(strs); i++ {
s := Trim(strs[i])
if len(s) > 0 {
v, err := strconv.ParseInt(s, 10, 64)
if err == nil {
rval = append(rval, int(v))
}
}
}
return
}
func StrToUInt8List(str string, sep string) (rval []byte) {
strs := strings.Split(str, sep)
rval = make([]byte, 0, len(strs))
for i := 0; i < len(strs); i++ {
s := Trim(strs[i])
if len(s) > 0 {
v, err := strconv.ParseInt(s, 10, 64)
if err == nil {
rval = append(rval, byte(v))
}
}
}
return
}
func Int8ListToStrs(lst []int8, sep string) string {
var bb strings.Builder
for i := 0; i < len(lst); i++ {
if bb.Len() > 0 {
bb.WriteString(sep)
}
bb.WriteString(fmt.Sprintf("%d", lst[i]))
}
return bb.String()
}
func StrToInt8List(str string, sep string) (rval []int8) {
strs := strings.Split(str, sep)
rval = make([]int8, 0, len(strs))
for i := 0; i < len(strs); i++ {
s := Trim(strs[i])
if len(s) > 0 {
v, err := strconv.ParseInt(s, 10, 64)
if err == nil {
rval = append(rval, int8(v))
}
}
}
return
}
func UInt8ListToStrs(lst []byte, sep string) string {
var bb strings.Builder
for i := 0; i < len(lst); i++ {
if bb.Len() > 0 {
bb.WriteString(sep)
}
bb.WriteString(fmt.Sprintf("%d", lst[i]))
}
return bb.String()
}
func StrToIntDef(s string, defval int) int {
v, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return defval
} else {
return int(v)
}
}
func StrToInt8Def(s string, defval int8) int8 {
return int8(StrToInt64Def(s, int64(defval)))
}
func StrToInt64Def(s string, defval int64) int64 {
v, err := strconv.ParseInt(s, 10, 64)
if err != nil {
if strings.HasPrefix(s, "0x") {
v, err := strconv.ParseInt(s[2:], 16, 64)
if err != nil {
return defval
} else {
return v
}
}
return defval
} else {
return int64(v)
}
}
func ReplaceReg(s string, regP string, new string) (string, error) {
reg, err := regexp.Compile(regP)
if err != nil {
return "", err
}
return string(reg.ReplaceAll([]byte(s), []byte(new))), nil
}
/*
*
s := "a b c d " -> "a b c d "
*/
func ReplaceMultiSpace2One(s string, new string) string {
str, err := ReplaceReg(s, "( )+", new)
if err != nil {
return s
}
return str
}
/*
*
ReplaceMultiAny2One("a b c d ", " ", ":"); -> "a:b:c:d:"
ReplaceMultiAny2One("a b c d "," "," ")->"a b c d "
ReplaceMultiAny2One("ababaaa aab ac d aaa ","ab","x")->"xaaa ax ac d aaa "
ReplaceMultiAny2One("aaaaa aab ac d aaa ", "aa", "x")->"xa xb ac d xa"
*/
func ReplaceMultiAny2One(s string, any, new string) string {
regP := fmt.Sprintf("(%s)+", regexp.QuoteMeta(any))
//fmt.Println(regP)
str, err := ReplaceReg(s, regP, new)
if err != nil {
return s
}
return str
}
/*
*
忽略大小写
`<td>a</td><td>b</td>`
ReplaceArea(str, "<td>", "</td>", "<td>abc</td>") = <td>abc</td><td>abc</td>
*/
func ReplaceArea(s string, start, end string, new string) string {
// regexp.MustCompile(`(?i:^hello).*Go`)
strRegFind := fmt.Sprintf("(?i:%s)[\\s\\S]*?(?i:%s)",
regexp.QuoteMeta(start), regexp.QuoteMeta(end))
reg, err := regexp.Compile(strRegFind)
if err != nil {
return s
}
return string(reg.ReplaceAll([]byte(s), []byte(new)))
}
/*
*
忽略大小写
*/
func ReplaceAll(s string, old, new string) string {
strRegFind := fmt.Sprintf("(?i)%s", regexp.QuoteMeta(old))
reg, err := regexp.Compile(strRegFind)
if err != nil {
return s
}
return string(reg.ReplaceAll([]byte(s), []byte(new)))
}
/*
*
不支持....
*/
func GetAreaBK(s string, start, end string, idx int) string {
// (?<=<td>).*?(?=</td>) // 不支持
strRegFind := fmt.Sprintf("(?<=%s).*?(?=%s)",
regexp.QuoteMeta(start), regexp.QuoteMeta(end))
reg, err := regexp.Compile(strRegFind)
if err != nil {
return s
}
return reg.FindString(s)
}
/*
*
查找s2中不存在与s1中的元素
FindNonElement("1,2,3", "3,4,2,5") = "4,5"
*/
func FindNonElement(s1, s2 string, sep rune) string {
rval := make([]rune, 0, len(s1))
RangeStringSep(s2, sep, func(idx int, s string) bool {
if !ContainElement(s1, s, sep) {
if len(rval) > 0 {
rval = append(rval, sep)
}
rval = append(rval, []rune(s)...)
}
return true
})
return string(rval)
}
/*
*
false = ContainElement("1,2,3,16", ",", "6")
*/
func ContainElement(s string, ele string, sep rune) (rval bool) {
RangeStringSep(s, sep, func(idx int, s1 string) bool {
rval = s1 == ele
return !rval
})
return
}
/*
`<td>a</td><td>b</td>`
GetBetween(str, "<td>", "</td>") = a
GetBetween("$now$", "$", "$") = "now"
*/
func GetBetweenEx(str string, start, end string, idx int) (ok bool, val string) {
j := 0
for {
n := strings.Index(str, start)
if n == -1 {
return false, ""
}
str = string([]byte(str)[n+len(start):])
m := strings.Index(str, end)
if m == -1 {
return false, ""
}
if j == idx {
str = string([]byte(str)[:m])
return true, str
} else {
str = string([]byte(str)[m+len(end):])
if len(str) <= len(start) {
return false, ""
}
}
j++
}
}
/*
`<td>a</td><td>b</td>`
GetBetween(str, "<td>", "</td>") = a
GetBetween("$now$", "$", "$") = "now"
*/
func GetBetween(str string, start, end string, idx int) string {
j := 0
for {
n := strings.Index(str, start)
if n == -1 {
return ""
}
str = string([]byte(str)[n+len(start):])
m := strings.Index(str, end)
if m == -1 {
return ""
}
if j == idx {
str = string([]byte(str)[:m])
return str
} else {
str = string([]byte(str)[m+len(end):])
if len(str) <= len(start) {
return ""
}
}
j++
}
}
func IsWindows() bool {
return runtime.GOOS == "windows"
}
func IsLinux() bool {
return runtime.GOOS == "linux"
}
type encoding int
const (
encodePath encoding = 1 + iota
encodePathSegment
encodeHost
encodeZone
encodeUserPassword
encodeQueryComponent
encodeFragment
)
type EscapeError string
func (e EscapeError) Error() string {
return "invalid URL escape " + strconv.Quote(string(e))
}
type InvalidHostError string
func (e InvalidHostError) Error() string {
return "invalid character " + strconv.Quote(string(e)) + " in host name"
}
const upperhex = "0123456789ABCDEF"
func ishex(c byte) bool {
switch {
case '0' <= c && c <= '9':
return true
case 'a' <= c && c <= 'f':
return true
case 'A' <= c && c <= 'F':
return true
}
return false
}
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
// Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 3986.
//
// Please be informed that for now shouldEscape does not check all
// reserved characters correctly. See golang.org/issue/5684.
func shouldEscape(c byte, mode encoding) bool {
// §2.3 Unreserved characters (alphanum)
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
return false
}
if mode == encodeHost || mode == encodeZone {
// §3.2.2 Host allows
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
// as part of reg-name.
// We add : because we include :port as part of host.
// We add [ ] because we include [ipv6]:port as part of host.
// We add < > because they're the only characters left that
// we could possibly allow, and Parse will reject them if we
// escape them (because hosts can't use %-encoding for
// ASCII bytes).
switch c {
case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']', '<', '>', '"':
return false
}
}
switch c {
case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
return false
case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
// Different sections of the URL allow a few of
// the reserved characters to appear unescaped.
switch mode {
case encodePath: // §3.3
// The RFC allows : @ & = + $ but saves / ; , for assigning
// meaning to individual path segments. This package
// only manipulates the path as a whole, so we allow those
// last three as well. That leaves only ? to escape.
return c == '?'
case encodePathSegment: // §3.3
// The RFC allows : @ & = + $ but saves / ; , for assigning
// meaning to individual path segments.
return c == '/' || c == ';' || c == ',' || c == '?'
case encodeUserPassword: // §3.2.1
// The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
// userinfo, so we must escape only '@', '/', and '?'.
// The parsing of userinfo treats ':' as special so we must escape
// that too.
return c == '@' || c == '/' || c == '?' || c == ':'
case encodeQueryComponent: // §3.4
// The RFC reserves (so we must escape) everything.
return true
case encodeFragment: // §4.1
// The RFC text is silent but the grammar allows
// everything, so escape nothing.
return false
}
}
if mode == encodeFragment {
// RFC 3986 §2.2 allows not escaping sub-delims. A subset of sub-delims are
// included in reserved from RFC 2396 §2.2. The remaining sub-delims do not
// need to be escaped. To minimize potential breakage, we apply two restrictions:
// (1) we always escape sub-delims outside of the fragment, and (2) we always
// escape single quote to avoid breaking callers that had previously assumed that
// single quotes would be escaped. See issue #19917.
switch c {
case '!', '(', ')', '*':
return false
}
}
// Everything else must be escaped.
return true
}
// QueryUnescape does the inverse transformation of QueryEscape,
// converting each 3-byte encoded substring of the form "%AB" into the
// hex-decoded byte 0xAB.
// It returns an error if any % is not followed by two hexadecimal
// digits.
func QueryUnescape(s string) (string, error) {
return unescape(s, encodeQueryComponent)
}
// PathUnescape does the inverse transformation of PathEscape,
// converting each 3-byte encoded substring of the form "%AB" into the
// hex-decoded byte 0xAB. It returns an error if any % is not followed
// by two hexadecimal digits.
//
// PathUnescape is identical to QueryUnescape except that it does not
// unescape '+' to ' ' (space).
func PathUnescape(s string) (string, error) {
return unescape(s, encodePathSegment)
}
// unescape unescapes a string; the mode specifies
// which section of the URL string is being unescaped.
func unescape(s string, mode encoding) (string, error) {
// Count %, check that they're well-formed.
n := 0
hasPlus := false
for i := 0; i < len(s); {
switch s[i] {
case '%':
n++
if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
s = s[i:]
if len(s) > 3 {
s = s[:3]
}
return "", EscapeError(s)
}
// Per https://tools.ietf.org/html/rfc3986#page-21
// in the host component %-encoding can only be used
// for non-ASCII bytes.
// But https://tools.ietf.org/html/rfc6874#section-2
// introduces %25 being allowed to escape a percent sign
// in IPv6 scoped-address literals. Yay.
if mode == encodeHost && unhex(s[i+1]) < 8 && s[i:i+3] != "%25" {
return "", EscapeError(s[i : i+3])
}
if mode == encodeZone {
// RFC 6874 says basically "anything goes" for zone identifiers
// and that even non-ASCII can be redundantly escaped,
// but it seems prudent to restrict %-escaped bytes here to those
// that are valid host name bytes in their unescaped form.
// That is, you can use escaping in the zone identifier but not
// to introduce bytes you couldn't just write directly.
// But Windows puts spaces here! Yay.
v := unhex(s[i+1])<<4 | unhex(s[i+2])
if s[i:i+3] != "%25" && v != ' ' && shouldEscape(v, encodeHost) {
return "", EscapeError(s[i : i+3])
}
}
i += 3
case '+':
hasPlus = mode == encodeQueryComponent
i++
default:
if (mode == encodeHost || mode == encodeZone) && s[i] < 0x80 && shouldEscape(s[i], mode) {
return "", InvalidHostError(s[i : i+1])
}
i++
}
}
if n == 0 && !hasPlus {
return s, nil
}
var t strings.Builder
t.Grow(len(s) - 2*n)
for i := 0; i < len(s); i++ {
switch s[i] {
case '%':
t.WriteByte(unhex(s[i+1])<<4 | unhex(s[i+2]))
i += 2
case '+':
if mode == encodeQueryComponent {
t.WriteByte(' ')
} else {
t.WriteByte('+')
}
default:
t.WriteByte(s[i])
}
}
return t.String(), nil
}
// QueryEscape escapes the string so it can be safely placed
// inside a URL query.
func QueryEscape(s string) string {
return escape(s, encodeQueryComponent)
}
// PathEscape escapes the string so it can be safely placed inside a URL path segment,
// replacing special characters (including /) with %XX sequences as needed.
func PathEscape(s string) string {
return escape(s, encodePathSegment)
}
func escape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
c := s[i]
if shouldEscape(c, mode) {
if c == ' ' && mode == encodeQueryComponent {
spaceCount++
} else {
hexCount++
}
}
}
if spaceCount == 0 && hexCount == 0 {
return s
}
var buf [64]byte
var t []byte
required := len(s) + 2*hexCount
if required <= len(buf) {
t = buf[:required]
} else {
t = make([]byte, required)
}
if hexCount == 0 {
copy(t, s)
for i := 0; i < len(s); i++ {
if s[i] == ' ' {
t[i] = '+'
}
}
return string(t)
}
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
case c == ' ' && mode == encodeQueryComponent:
t[j] = '+'
j++
case shouldEscape(c, mode):
t[j] = '%'
t[j+1] = upperhex[c>>4]
t[j+2] = upperhex[c&15]
j += 3
default:
t[j] = s[i]
j++
}
}
return string(t)
}
type StrMap map[string]string
func NewStrMap() StrMap {
return make(StrMap)
}
func NewStrMapFromURLStr(s string) StrMap {
strmap := NewStrMap()
strmap.URLFormDecode(s)
return strmap
}
func NewStrMapEx(s, kvsep, itmsep string) StrMap {
r := make(StrMap)
r.ParseKVPairs(s, kvsep, itmsep)
return r
}
func (this StrMap) Reset() {
for k := range this {
delete(this, k)
}
}
// ExecReplace 利用映射关系进行替换, key -> value
func (this StrMap) ExecReplace(s string) string {
for k, v := range this {
s = ReplaceAll(s, k, v)
}
return s
}
func (this StrMap) SortRange(fn func(k, v string) bool) {
if this == nil {
return
}
keys := make([]string, 0, len(this))
for k := range this {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := this[k]
if !fn(k, v) {
break
}
}
}
func (this StrMap) SortRangeEncode(kvspliter string, itmspliter string, fn func(k, v string) bool) string {
if this == nil {
return ""
}
var buf strings.Builder
this.SortRange(func(k, v string) bool {
if fn(k, v) {
if buf.Len() > 0 {
buf.WriteString(itmspliter)
}
buf.WriteString(k)
buf.WriteString(kvspliter)
buf.WriteString(v)
}
return true
})
return buf.String()
}
func (this StrMap) Encode(kvspliter string, itmspliter string) string {
if this == nil {
return ""
}
var buf strings.Builder
keys := make([]string, 0, len(this))
for k := range this {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
if buf.Len() > 0 {
buf.WriteString(itmspliter)
}
v := this[k]
buf.WriteString(k)
buf.WriteString(kvspliter)
buf.WriteString(v)
}
return buf.String()
}
func MapEncode(strMap map[string]string, kvsep, itmsep string, escapeflag bool, bb io.Writer) {
keys := make([]string, 0, len(strMap))
for k := range strMap {
keys = append(keys, k)
}
sort.Strings(keys)
i := 0
for _, k := range keys {
v := strMap[k]
if i > 0 {
bb.Write([]byte(itmsep))
}
if escapeflag {
keyEscaped := QueryEscape(k)
bb.Write([]byte(keyEscaped))
bb.Write([]byte(kvsep))
bb.Write([]byte(QueryEscape(v)))
} else {
bb.Write([]byte(k))
bb.Write([]byte(kvsep))
bb.Write([]byte(v))
}
i++
}
}
func (this StrMap) DeleteByKeylst(keylst ...string) (r int) {
for _, k := range keylst {
delete(this, k)
r++
}
return
}
func (this StrMap) URLFormEncodeKeylst(keylst ...string) string {
var sb strings.Builder
for _, k := range keylst {
if v, ok := this[k]; ok {
if sb.Len() > 0 {
sb.WriteByte('&')
}
keyEscaped := QueryEscape(k)
sb.WriteString(keyEscaped)
sb.WriteByte('=')
sb.WriteString(QueryEscape(v))
}
}
return sb.String()
}
func (this StrMap) URLFormEncode() string {
if this == nil {
return ""
}
var buf strings.Builder
keys := make([]string, 0, len(this))
for k := range this {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := this[k]
keyEscaped := QueryEscape(k)
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(keyEscaped)
buf.WriteByte('=')
buf.WriteString(QueryEscape(v))
}
return buf.String()
}
func (this StrMap) URLFormDecode(s string) {
lst := strings.Split(s, "&")
if len(lst) == 0 {
return
}
for i := 0; i < len(lst); i++ {
k, v := Split2Str(lst[i], "=")
k, _ = QueryUnescape(k)
v, _ = QueryUnescape(v)
if len(k) > 0 {
this[k] = v
}
}
}
func (this StrMap) CopyFrom(src StrMap) {
for k, v := range src {
this[k] = v
}
}
func (this StrMap) ParseKVPairsEx(s string, kvsep string, itmsep string, keylower bool) {
lst := strings.Split(s, itmsep)
if len(lst) == 0 {
return
}
for i := 0; i < len(lst); i++ {
k, v := Split2Str(lst[i], kvsep)
if len(k) > 0 {
if keylower {
k = strings.ToLower(k)
}
this[k] = v
}
}
}
func (this StrMap) ParseKVPairs(s string, kvsep string, itmsep string) {
lst := strings.Split(s, itmsep)
if len(lst) == 0 {
return
}
for i := 0; i < len(lst); i++ {
k, v := Split2Str(lst[i], kvsep)
k = Trim(k)
if len(k) > 0 {
this[k] = v
}
}
}
func (this StrMap) StringByName(k string, def string) string {
if v, ok := this[k]; ok {
return v
} else {
return def
}
}
func (this StrMap) IntByName(k string, def int) int {
if v, ok := this[k]; ok {
if len(v) == 0 {
return def
}
return StrToIntDef(v, def)
} else {
return def
}
}
func (this StrMap) Float64ByName(k string, def float64) float64 {
if v, ok := this[k]; ok {
return StrToFloat64Def(v, def)
} else {
return def
}
}
func (this StrMap) U8ByName(k string, def byte) byte {
return byte(this.IntByName(k, int(def)))
}
func (this StrMap) Int8ByName(k string, def int8) int8 {
return int8(this.IntByName(k, int(def)))
}
func (this StrMap) Int16ByName(k string, def int16) int16 {
return int16(this.IntByName(k, int(def)))
}
func (this StrMap) UnixTimeByName(k string, def time.Time) time.Time {
v := this.IntByName(k, -99999)
if v == -99999 {
return def
} else {
return time.Unix(int64(v), 0)
}
}
/*
解析命令行
XX.exe -a=v
*/
func (this StrMap) ParseCmdArgs(args []string) {
for i := 0; i < len(args); i++ {
s1, s2 := Split2Str(args[i], "=")
if len(s1) > 0 {
if s1[0] == '-' {
s1 = s1[1:]
}
if len(s2) == 0 {
s2 = s1
if i == 0 {
this["0"] = s1
} else {
this[s1] = s2
}
} else {
_, s2 = CheckTrimQuoteChr(s2, QUOTECHR, QUOTECHR)
this[s1] = s2
}
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。