github.com/PandaGoAdmin/utils@v0.0.0-20211208134815-d5461603a00f/string.go (about)

     1  package kgo
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/md5"
     6  	crand "crypto/rand"
     7  	"crypto/rsa"
     8  	"crypto/x509"
     9  	"encoding/base64"
    10  	"encoding/gob"
    11  	"encoding/hex"
    12  	"encoding/json"
    13  	"encoding/pem"
    14  	"errors"
    15  	"fmt"
    16  	"github.com/json-iterator/go"
    17  	xhtml "golang.org/x/net/html"
    18  	"golang.org/x/text/encoding/simplifiedchinese"
    19  	"golang.org/x/text/encoding/traditionalchinese"
    20  	"golang.org/x/text/transform"
    21  	"golang.org/x/text/width"
    22  	"golang.org/x/text/cases"
    23  	"golang.org/x/text/language"
    24  	"hash/crc32"
    25  	"html"
    26  	"io"
    27  	"io/ioutil"
    28  	"math"
    29  	"math/rand"
    30  	"net"
    31  	"net/http"
    32  	"net/url"
    33  	"regexp"
    34  	"strconv"
    35  	"strings"
    36  	"time"
    37  	"unicode"
    38  	"unicode/utf8"
    39  )
    40  
    41  // Md5 获取字节切片md5值.
    42  // length指定结果长度,默认32.
    43  func (ks *LkkString) Md5Byte(str []byte, length ...uint8) []byte {
    44  	var l uint8 = 32
    45  	if len(length) > 0 {
    46  		l = length[0]
    47  	}
    48  
    49  	return md5Byte(str, l)
    50  }
    51  
    52  // Md5 获取字符串md5值.
    53  // length指定结果长度,默认32.
    54  func (ks *LkkString) Md5(str string, length ...uint8) string {
    55  	var l uint8 = 32
    56  	if len(length) > 0 {
    57  		l = length[0]
    58  	}
    59  
    60  	return string(md5Byte([]byte(str), l))
    61  }
    62  
    63  // IsMd5 是否md5值.
    64  func (ks *LkkString) IsMd5(str string) bool {
    65  	return str != "" && RegMd5.MatchString(str)
    66  }
    67  
    68  // ShaXByte 计算字节切片的 shaX 散列值,x为1/256/512 .
    69  func (ks *LkkString) ShaXByte(str []byte, x uint16) []byte {
    70  	return shaXByte(str, x)
    71  }
    72  
    73  // ShaX 计算字符串的 shaX 散列值,x为1/256/512 .
    74  func (ks *LkkString) ShaX(str string, x uint16) string {
    75  	return string(shaXByte([]byte(str), x))
    76  }
    77  
    78  // IsSha1 是否Sha1值.
    79  func (ks *LkkString) IsSha1(str string) bool {
    80  	return str != "" && RegSha1.MatchString(str)
    81  }
    82  
    83  // IsSha256 是否Sha256值.
    84  func (ks *LkkString) IsSha256(str string) bool {
    85  	return str != "" && RegSha256.MatchString(str)
    86  }
    87  
    88  // IsSha512 是否Sha512值.
    89  func (ks *LkkString) IsSha512(str string) bool {
    90  	return str != "" && RegSha512.MatchString(str)
    91  }
    92  
    93  // Index 查找子串sub在字符串str中第一次出现的位置,不存在则返回-1;
    94  // ignoreCase为是否忽略大小写.
    95  func (ks *LkkString) Index(str, sub string, ignoreCase bool) int {
    96  	if str == "" || sub == "" {
    97  		return -1
    98  	}
    99  
   100  	if ignoreCase {
   101  		str = strings.ToLower(str)
   102  		sub = strings.ToLower(sub)
   103  	}
   104  
   105  	return strings.Index(str, sub)
   106  }
   107  
   108  // LastIndex 查找子串sub在字符串str中最后一次出现的位置,不存在则返回-1;
   109  // ignoreCase为是否忽略大小写.
   110  func (ks *LkkString) LastIndex(str, sub string, ignoreCase bool) int {
   111  	if str == "" || sub == "" {
   112  		return -1
   113  	}
   114  
   115  	if ignoreCase {
   116  		str = strings.ToLower(str)
   117  		sub = strings.ToLower(sub)
   118  	}
   119  
   120  	return strings.LastIndex(str, sub)
   121  }
   122  
   123  // Addslashes 使用反斜线引用字符串.
   124  func (ks *LkkString) Addslashes(str string) string {
   125  	var buf bytes.Buffer
   126  	for _, char := range str {
   127  		switch char {
   128  		case '\'', '"', '\\':
   129  			buf.WriteRune('\\')
   130  		}
   131  		buf.WriteRune(char)
   132  	}
   133  	return buf.String()
   134  }
   135  
   136  // Stripslashes 反引用一个引用字符串.
   137  func (ks *LkkString) Stripslashes(str string) string {
   138  	var buf bytes.Buffer
   139  	l, skip := len(str), false
   140  	for i, char := range str {
   141  		if skip {
   142  			skip = false
   143  		} else if char == '\\' {
   144  			if i+1 < l && str[i+1] == '\\' {
   145  				skip = true
   146  			}
   147  			continue
   148  		}
   149  		buf.WriteRune(char)
   150  	}
   151  	return buf.String()
   152  }
   153  
   154  // JsonEncode 对val变量进行 JSON 编码.
   155  // 依赖库github.com/json-iterator/go.
   156  func (ks *LkkString) JsonEncode(val interface{}) ([]byte, error) {
   157  	var jsons = jsoniter.ConfigCompatibleWithStandardLibrary
   158  	return jsons.Marshal(val)
   159  }
   160  
   161  // JsonDecode 对 JSON 格式的str字符串进行解码,注意res使用指针.
   162  // 依赖库github.com/json-iterator/go.
   163  func (ks *LkkString) JsonDecode(str []byte, res interface{}) error {
   164  	var jsons = jsoniter.ConfigCompatibleWithStandardLibrary
   165  	return jsons.Unmarshal(str, res)
   166  }
   167  
   168  // Utf8ToGbk UTF-8转GBK编码.
   169  func (ks *LkkString) Utf8ToGbk(s []byte) ([]byte, error) {
   170  	reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder())
   171  	d, e := io.ReadAll(reader)
   172  	return d, e
   173  }
   174  
   175  // GbkToUtf8 GBK转UTF-8编码.
   176  func (ks *LkkString) GbkToUtf8(s []byte) ([]byte, error) {
   177  	reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
   178  	d, e := io.ReadAll(reader)
   179  	return d, e
   180  }
   181  
   182  // IsUtf8 字符串是否UTF-8编码.
   183  func (ks *LkkString) IsUtf8(s []byte) bool {
   184  	return utf8.Valid(s)
   185  }
   186  
   187  // IsGbk 字符串是否GBK编码.
   188  func (ks *LkkString) IsGbk(s []byte) (res bool) {
   189  	length := len(s)
   190  	var i, j int
   191  	for i < length {
   192  		j = i + 1
   193  		//大于127的使用双字节编码,且落在gbk编码范围内的字符
   194  		//GBK中每个汉字包含两个字节,第一个字节(首字节)的范围是0x81-0xFE(即129-254),第二个字节(尾字节)的范围是0x40-0xFE(即64-254)
   195  		if s[i] > 0x7f && j < length {
   196  			if s[i] >= 0x81 &&
   197  				s[i] <= 0xfe &&
   198  				s[j] >= 0x40 &&
   199  				s[j] <= 0xfe {
   200  				i += 2
   201  				res = true
   202  			} else {
   203  				res = false
   204  				break
   205  			}
   206  		} else {
   207  			i++
   208  		}
   209  	}
   210  
   211  	return
   212  }
   213  
   214  // Img2Base64 将图片字节转换为base64字符串.ext为图片扩展名,默认jpg.
   215  func (ks *LkkString) Img2Base64(content []byte, ext ...string) string {
   216  	var imgType string = "jpg"
   217  	if len(ext) > 0 {
   218  		imgType = strings.ToLower(ext[0])
   219  	}
   220  
   221  	return img2Base64(content, imgType)
   222  }
   223  
   224  // StartsWith 字符串str是否以sub开头.
   225  func (ks *LkkString) StartsWith(str, sub string, ignoreCase bool) bool {
   226  	if str != "" && sub != "" {
   227  		i := ks.Index(str, sub, ignoreCase)
   228  		return i == 0
   229  	}
   230  
   231  	return false
   232  }
   233  
   234  // StartsWiths 字符串str是否以subs其中之一为开头.
   235  func (ks *LkkString) StartsWiths(str string, subs []string, ignoreCase bool) (res bool) {
   236  	for _, sub := range subs {
   237  		res = ks.StartsWith(str, sub, ignoreCase)
   238  		if res {
   239  			break
   240  		}
   241  	}
   242  	return
   243  }
   244  
   245  // EndsWith 字符串str是否以sub结尾.
   246  func (ks *LkkString) EndsWith(str, sub string, ignoreCase bool) bool {
   247  	if str != "" && sub != "" {
   248  		i := ks.LastIndex(str, sub, ignoreCase)
   249  		return i != -1 && (len(str)-len(sub)) == i
   250  	}
   251  
   252  	return false
   253  }
   254  
   255  // EndsWiths 字符串str是否以subs其中之一为结尾.
   256  func (ks *LkkString) EndsWiths(str string, subs []string, ignoreCase bool) (res bool) {
   257  	for _, sub := range subs {
   258  		res = ks.EndsWith(str, sub, ignoreCase)
   259  		if res {
   260  			break
   261  		}
   262  	}
   263  	return
   264  }
   265  
   266  // Trim 去除字符串首尾处的空白字符(或者其他字符).
   267  // characterMask为要修剪的字符.
   268  func (ks *LkkString) Trim(str string, characterMask ...string) string {
   269  	mask := getTrimMask(characterMask)
   270  	return strings.Trim(str, mask)
   271  }
   272  
   273  // Ltrim 删除字符串开头的空白字符(或其他字符).
   274  // characterMask为要修剪的字符.
   275  func (ks *LkkString) Ltrim(str string, characterMask ...string) string {
   276  	mask := getTrimMask(characterMask)
   277  	return strings.TrimLeft(str, mask)
   278  }
   279  
   280  // Rtrim 删除字符串末端的空白字符(或者其他字符).
   281  // characterMask为要修剪的字符.
   282  func (ks *LkkString) Rtrim(str string, characterMask ...string) string {
   283  	mask := getTrimMask(characterMask)
   284  	return strings.TrimRight(str, mask)
   285  }
   286  
   287  // TrimBOM 移除字符串中的BOM
   288  func (ks *LkkString) TrimBOM(str []byte) []byte {
   289  	return bytes.Trim(str, bomChars)
   290  }
   291  
   292  // IsEmpty 字符串是否为空(包括空格).
   293  func (ks *LkkString) IsEmpty(str string) bool {
   294  	if str == "" || len(ks.Trim(str)) == 0 {
   295  		return true
   296  	}
   297  
   298  	return false
   299  }
   300  
   301  // IsLetters 字符串是否全(英文)字母组成.
   302  func (ks *LkkString) IsLetters(str string) bool {
   303  	for _, r := range str {
   304  		if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') {
   305  			return false
   306  		}
   307  	}
   308  	return str != ""
   309  }
   310  
   311  // IsUpper 字符串是否全部大写.
   312  func (ks *LkkString) IsUpper(str string) bool {
   313  	for _, r := range str {
   314  		if !unicode.IsUpper(r) && unicode.IsLetter(r) {
   315  			return false
   316  		}
   317  	}
   318  	return str != ""
   319  }
   320  
   321  // IsLower 字符串是否全部小写.
   322  func (ks *LkkString) IsLower(str string) bool {
   323  	for _, r := range str {
   324  		if !unicode.IsLower(r) && unicode.IsLetter(r) {
   325  			return false
   326  		}
   327  	}
   328  	return str != ""
   329  }
   330  
   331  // HasLetter 字符串是否含有(英文)字母.
   332  func (ks *LkkString) HasLetter(str string) bool {
   333  	for _, r := range str {
   334  		if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
   335  			return true
   336  		}
   337  	}
   338  	return false
   339  }
   340  
   341  // IsASCII 是否ASCII字符串.
   342  func (ks *LkkString) IsASCII(str string) bool {
   343  	//return str != "" && RegAscii.MatchString(str)
   344  	n := len(str)
   345  	for i := 0; i < n; i++ {
   346  		if str[i] > 127 {
   347  			return false
   348  		}
   349  	}
   350  
   351  	return str != ""
   352  }
   353  
   354  // IsMultibyte 字符串是否含有多字节字符.
   355  func (ks *LkkString) IsMultibyte(str string) bool {
   356  	return str != "" && RegMultiByte.MatchString(str)
   357  }
   358  
   359  // HasFullWidth 是否含有全角字符.
   360  func (ks *LkkString) HasFullWidth(str string) bool {
   361  	return str != "" && RegFullWidth.MatchString(str)
   362  }
   363  
   364  // HasHalfWidth 是否含有半角字符.
   365  func (ks *LkkString) HasHalfWidth(str string) bool {
   366  	return str != "" && RegHalfWidth.MatchString(str)
   367  }
   368  
   369  // IsEnglish 字符串是否纯英文.letterCase是否检查大小写,枚举值(CASE_NONE,CASE_LOWER,CASE_UPPER).
   370  func (ks *LkkString) IsEnglish(str string, letterCase LkkCaseSwitch) bool {
   371  	switch letterCase {
   372  	case CASE_LOWER:
   373  		return str != "" && RegAlphaLower.MatchString(str)
   374  	case CASE_UPPER:
   375  		return str != "" && RegAlphaUpper.MatchString(str)
   376  	default: //CASE_NONE
   377  		return ks.IsLetters(str)
   378  	}
   379  }
   380  
   381  // HasEnglish 是否含有英文字符,HasLetter的别名.
   382  func (ks *LkkString) HasEnglish(str string) bool {
   383  	return ks.HasLetter(str)
   384  }
   385  
   386  // HasChinese 字符串是否含有中文.
   387  func (ks *LkkString) HasChinese(str string) bool {
   388  	for _, r := range str {
   389  		if unicode.Is(unicode.Scripts["Han"], r) {
   390  			return true
   391  		}
   392  	}
   393  
   394  	return false
   395  }
   396  
   397  // IsChinese 字符串是否全部中文.
   398  func (ks *LkkString) IsChinese(str string) bool {
   399  	return str != "" && RegChineseAll.MatchString(str)
   400  }
   401  
   402  // IsChineseName 字符串是否中文名称.
   403  func (ks *LkkString) IsChineseName(str string) bool {
   404  	return str != "" && RegChineseName.MatchString(str)
   405  }
   406  
   407  // IsWord 是否词语(不以下划线开头的中文、英文、数字、下划线).
   408  func (ks *LkkString) IsWord(str string) bool {
   409  	return str != "" && RegWord.MatchString(str)
   410  }
   411  
   412  // IsNumeric 字符串是否数值(不包含复数和科学计数法).
   413  func (ks *LkkString) IsNumeric(str string) bool {
   414  	if str == "" {
   415  		return false
   416  	}
   417  	_, err := strconv.ParseFloat(str, 64)
   418  	return err == nil
   419  }
   420  
   421  // IsAlphaNumeric 是否字母或数字.
   422  func (ks *LkkString) IsAlphaNumeric(str string) bool {
   423  	return str != "" && RegAlphaNumeric.MatchString(str)
   424  }
   425  
   426  // HasSpecialChar 字符串是否含有特殊字符.
   427  func (ks *LkkString) HasSpecialChar(str string) bool {
   428  	for _, r := range str {
   429  		// IsPunct 判断 r 是否为一个标点字符 (类别 P)
   430  		// IsSymbol 判断 r 是否为一个符号字符
   431  		// IsMark 判断 r 是否为一个 mark 字符 (类别 M)
   432  		if unicode.IsPunct(r) || unicode.IsSymbol(r) || unicode.IsMark(r) {
   433  			return true
   434  		}
   435  	}
   436  
   437  	return false
   438  }
   439  
   440  // IsJSON 字符串是否合法的json格式.
   441  func (ks *LkkString) IsJSON(str string) bool {
   442  	length := len(str)
   443  	if length == 0 {
   444  		return false
   445  	} else if (str[0] != '{' || str[length-1] != '}') && (str[0] != '[' || str[length-1] != ']') {
   446  		return false
   447  	}
   448  
   449  	var js json.RawMessage
   450  	return json.Unmarshal([]byte(str), &js) == nil
   451  }
   452  
   453  // IsIP 检查字符串是否IP地址.
   454  func (ks *LkkString) IsIP(str string) bool {
   455  	return str != "" && net.ParseIP(str) != nil
   456  }
   457  
   458  // IsIPv4 检查字符串是否IPv4地址.
   459  func (ks *LkkString) IsIPv4(str string) bool {
   460  	ipAddr := net.ParseIP(str)
   461  	// 不是合法的IP地址
   462  	if ipAddr == nil {
   463  		return false
   464  	}
   465  
   466  	return ipAddr.To4() != nil && strings.ContainsRune(str, '.')
   467  }
   468  
   469  // IsIPv6 检查字符串是否IPv6地址.
   470  func (ks *LkkString) IsIPv6(str string) bool {
   471  	ipAddr := net.ParseIP(str)
   472  	return ipAddr != nil && strings.ContainsRune(str, ':')
   473  }
   474  
   475  // IsDNSName 是否DNS名称.
   476  func (ks *LkkString) IsDNSName(str string) bool {
   477  	if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 {
   478  		// constraints already violated
   479  		return false
   480  	}
   481  	return !ks.IsIP(str) && RegDNSname.MatchString(str)
   482  }
   483  
   484  // IsHost 字符串是否主机名(IP或DNS名称).
   485  func (ks *LkkString) IsHost(str string) bool {
   486  	return ks.IsIP(str) || ks.IsDNSName(str)
   487  }
   488  
   489  // IsDialAddr 是否网络拨号地址(形如127.0.0.1:80),用于net.Dial()检查.
   490  func (ks *LkkString) IsDialAddr(str string) bool {
   491  	h, p, err := net.SplitHostPort(str)
   492  	if err == nil && h != "" && p != "" && (ks.IsDNSName(h) || ks.IsIP(h)) && isPort(p) {
   493  		return true
   494  	}
   495  
   496  	return false
   497  }
   498  
   499  // IsMACAddr 是否MAC物理网卡地址.
   500  func (ks *LkkString) IsMACAddr(str string) bool {
   501  	_, err := net.ParseMAC(str)
   502  	return err == nil
   503  }
   504  
   505  // IsEmail 检查字符串是否邮箱.参数validateTrue,是否验证邮箱主机的真实性.
   506  func (ks *LkkString) IsEmail(email string, validateHost bool) (bool, error) {
   507  	//长度检查
   508  	length := len(email)
   509  	at := strings.LastIndexByte(email, '@')
   510  	if (length < 6 || length > 254) || (at <= 0 || at > length-3) {
   511  		return false, fmt.Errorf("[IsEmail] invalid email length")
   512  	}
   513  
   514  	//验证邮箱格式
   515  	chkFormat := RegEmail.MatchString(email)
   516  	if !chkFormat {
   517  		return false, fmt.Errorf("[IsEmail] invalid email format")
   518  	}
   519  
   520  	//验证主机
   521  	if validateHost {
   522  		host := email[at+1:]
   523  		if _, err := net.LookupMX(host); err != nil {
   524  			//因无法确定mx主机的smtp端口,所以去掉Hello/Mail/Rcpt检查邮箱是否存在
   525  			//仅检查主机是否有效
   526  			if _, err := net.LookupIP(host); err != nil {
   527  				return false, err
   528  			}
   529  		}
   530  	}
   531  
   532  	return true, nil
   533  }
   534  
   535  // IsMobilecn 检查字符串是否中国大陆手机号.
   536  func (ks *LkkString) IsMobilecn(str string) bool {
   537  	return str != "" && RegMobilecn.MatchString(str)
   538  }
   539  
   540  // IsTel 是否固定电话或400/800电话.
   541  func (ks *LkkString) IsTel(str string) bool {
   542  	return str != "" && RegTelephone.MatchString(str)
   543  }
   544  
   545  // IsPhone 是否电话号码(手机或固话).
   546  func (ks *LkkString) IsPhone(str string) bool {
   547  	return str != "" && RegPhone.MatchString(str)
   548  }
   549  
   550  // IsCreditNo 检查是否(15或18位)身份证号码,并返回经校验的号码.
   551  func (ks *LkkString) IsCreditNo(str string) (bool, string) {
   552  	chk := str != "" && RegCreditno.MatchString(str)
   553  	if !chk {
   554  		return false, ""
   555  	}
   556  
   557  	// 检查省份代码
   558  	if _, chk = CreditArea[str[0:2]]; !chk {
   559  		return false, ""
   560  	}
   561  
   562  	// 将15位身份证升级到18位
   563  	leng := len(str)
   564  	if leng == 15 {
   565  		// 先转为17位,如果身份证顺序码是996 997 998 999,这些是为百岁以上老人的特殊编码
   566  		if chk, _ = ks.Dstrpos(str[12:], []string{"996", "997", "998", "999"}, false); chk {
   567  			str = str[0:6] + "18" + str[6:]
   568  		} else {
   569  			str = str[0:6] + "19" + str[6:]
   570  		}
   571  
   572  		// 再加上校验码
   573  		code := append([]byte{}, creditChecksum(str))
   574  		str += string(code)
   575  	}
   576  
   577  	// 检查生日
   578  	birthday := str[6:10] + "-" + str[10:12] + "-" + str[12:14]
   579  	chk, tim := KTime.IsDate2time(birthday)
   580  	now := KTime.UnixTime()
   581  	if !chk {
   582  		return false, ""
   583  	} else if tim >= now {
   584  		return false, ""
   585  	}
   586  
   587  	// 18位身份证需要验证最后一位校验位
   588  	if leng == 18 {
   589  		str = strings.ToUpper(str)
   590  		if str[17] != creditChecksum(str) {
   591  			return false, ""
   592  		}
   593  	}
   594  
   595  	return true, str
   596  }
   597  
   598  // IsHexcolor 检查是否十六进制颜色,并返回带"#"的修正值.
   599  func (ks *LkkString) IsHexcolor(str string) (bool, string) {
   600  	chk := str != "" && RegHexcolor.MatchString(str)
   601  	if chk && !strings.ContainsRune(str, '#') {
   602  		str = "#" + strings.ToUpper(str)
   603  	}
   604  	return chk, str
   605  }
   606  
   607  // IsRGBcolor 检查字符串是否RGB颜色格式.
   608  func (ks *LkkString) IsRGBcolor(str string) bool {
   609  	return str != "" && RegRgbcolor.MatchString(str)
   610  }
   611  
   612  // IsBlank 是否空(空白)字符串.
   613  func (ks *LkkString) IsBlank(str string) bool {
   614  	// Check length
   615  	if len(str) > 0 {
   616  		// Iterate string
   617  		for i := range str {
   618  			// Check about char different from whitespace
   619  			// 227为全角空格
   620  			if str[i] > 32 && str[i] != 227 {
   621  				return false
   622  			}
   623  		}
   624  	}
   625  	return true
   626  }
   627  
   628  // IsWhitespaces 是否全部空白字符,不包括空字符串.
   629  func (ks *LkkString) IsWhitespaces(str string) bool {
   630  	return str != "" && RegWhitespaceAll.MatchString(str)
   631  }
   632  
   633  // HasWhitespace 是否带有空白字符.
   634  func (ks *LkkString) HasWhitespace(str string) bool {
   635  	return str != "" && RegWhitespaceHas.MatchString(str)
   636  }
   637  
   638  // IsBase64 是否base64字符串.
   639  func (ks *LkkString) IsBase64(str string) bool {
   640  	return str != "" && RegBase64.MatchString(str)
   641  }
   642  
   643  // IsBase64Image 是否base64编码的图片.
   644  func (ks *LkkString) IsBase64Image(str string) bool {
   645  	if str == "" || !strings.ContainsRune(str, ',') {
   646  		return false
   647  	}
   648  
   649  	dataURI := strings.Split(str, ",")
   650  	return RegBase64Image.MatchString(dataURI[0]) && RegBase64.MatchString(dataURI[1])
   651  }
   652  
   653  // IsRsaPublicKey 检查字符串是否RSA的公钥,keylen为密钥长度.
   654  func (ks *LkkString) IsRsaPublicKey(str string, keylen uint16) bool {
   655  	bb := bytes.NewBufferString(str)
   656  	pemBytes, _ := ioutil.ReadAll(bb)
   657  
   658  	// 获取公钥
   659  	block, _ := pem.Decode(pemBytes)
   660  	if block != nil && block.Type != "PUBLIC KEY" {
   661  		return false
   662  	}
   663  	var der []byte
   664  	var err error
   665  
   666  	if block != nil {
   667  		der = block.Bytes
   668  	} else {
   669  		der, err = base64.StdEncoding.DecodeString(str)
   670  		if err != nil {
   671  			return false
   672  		}
   673  	}
   674  
   675  	key, err := x509.ParsePKIXPublicKey(der)
   676  	if err != nil {
   677  		return false
   678  	}
   679  	pubkey, ok := key.(*rsa.PublicKey)
   680  	if !ok {
   681  		return false
   682  	}
   683  	bitlen := len(pubkey.N.Bytes()) * 8
   684  	return bitlen == int(keylen)
   685  }
   686  
   687  // IsUrl 检查字符串是否URL.
   688  func (ks *LkkString) IsUrl(str string) bool {
   689  	if str == "" || len(str) <= 3 || utf8.RuneCountInString(str) >= 2083 || strings.HasPrefix(str, ".") {
   690  		return false
   691  	}
   692  
   693  	res, err := url.ParseRequestURI(str)
   694  	if err != nil {
   695  		return false //Couldn't even parse the url
   696  	}
   697  	if len(res.Scheme) == 0 {
   698  		return false //No Scheme found
   699  	}
   700  
   701  	return true
   702  }
   703  
   704  // IsUrlExists 检查URL是否存在.
   705  func (ks *LkkString) IsUrlExists(str string) bool {
   706  	if !ks.IsUrl(str) {
   707  		return false
   708  	}
   709  
   710  	client := &http.Client{}
   711  	resp, err := client.Head(str)
   712  	if err != nil {
   713  		return false
   714  	} else if resp.StatusCode == 404 {
   715  		return false
   716  	}
   717  
   718  	return true
   719  }
   720  
   721  // Jsonp2Json 将jsonp转为json串.
   722  // Example: forbar({a:"1",b:2}) to {"a":"1","b":2}
   723  func (ks *LkkString) Jsonp2Json(str string) (string, error) {
   724  	start := strings.Index(str, "(")
   725  	end := strings.LastIndex(str, ")")
   726  
   727  	if start == -1 || end == -1 {
   728  		return "", errors.New("[Jsonp2Json] invalid jsonp.")
   729  	}
   730  
   731  	start += 1
   732  	if start >= end {
   733  		return "", errors.New("[Jsonp2Json] invalid jsonp.")
   734  	}
   735  
   736  	res := str[start:end]
   737  
   738  	return res, nil
   739  }
   740  
   741  // Strpos 查找字符串首次出现的位置,找不到时返回-1.
   742  // haystack在该字符串中进行查找,needle要查找的字符串;
   743  // offset起始位置,为负数时时,搜索会从字符串结尾指定字符数开始.
   744  func (ks *LkkString) Strpos(haystack, needle string, offset int) int {
   745  	length := len(haystack)
   746  	if length == 0 || offset > length || -offset > length {
   747  		return -1
   748  	}
   749  
   750  	if offset < 0 {
   751  		offset += length
   752  	}
   753  	pos := strings.Index(haystack[offset:], needle)
   754  	if pos == -1 {
   755  		return -1
   756  	}
   757  	return pos + offset
   758  }
   759  
   760  // Stripos  查找字符串首次出现的位置(不区分大小写),找不到时返回-1.
   761  // haystack在该字符串中进行查找,needle要查找的字符串;
   762  // offset起始位置,为负数时时,搜索会从字符串结尾指定字符数开始.
   763  func (ks *LkkString) Stripos(haystack, needle string, offset int) int {
   764  	length := len(haystack)
   765  	if length == 0 || offset > length || -offset > length {
   766  		return -1
   767  	}
   768  
   769  	if offset < 0 {
   770  		offset += length
   771  	}
   772  	pos := ks.Index(haystack[offset:], needle, true)
   773  	if pos == -1 {
   774  		return -1
   775  	}
   776  	return pos + offset
   777  }
   778  
   779  // Strrpos 查找指定字符串在目标字符串中最后一次出现的位置.
   780  func (ks *LkkString) Strrpos(haystack, needle string, offset int) int {
   781  	pos, length := 0, len(haystack)
   782  	if length == 0 || offset > length || -offset > length {
   783  		return -1
   784  	}
   785  
   786  	if offset < 0 {
   787  		haystack = haystack[:offset+length+1]
   788  	} else {
   789  		haystack = haystack[offset:]
   790  	}
   791  	pos = strings.LastIndex(haystack, needle)
   792  	if offset > 0 && pos != -1 {
   793  		pos += offset
   794  	}
   795  	return pos
   796  }
   797  
   798  // Strripos 查找指定字符串在目标字符串中最后一次出现的位置(不区分大小写).
   799  func (ks *LkkString) Strripos(haystack, needle string, offset int) int {
   800  	pos, length := 0, len(haystack)
   801  	if length == 0 || offset > length || -offset > length {
   802  		return -1
   803  	}
   804  
   805  	if offset < 0 {
   806  		haystack = haystack[:offset+length+1]
   807  	} else {
   808  		haystack = haystack[offset:]
   809  	}
   810  	pos = ks.LastIndex(haystack, needle, true)
   811  	if offset > 0 && pos != -1 {
   812  		pos += offset
   813  	}
   814  	return pos
   815  }
   816  
   817  // Dstrpos 检查字符串str是否包含数组arr的元素之一,返回检查结果和匹配的字符串.
   818  // chkCase为是否检查大小写.
   819  func (ks *LkkString) Dstrpos(str string, arr []string, chkCase bool) (bool, string) {
   820  	if len(str) == 0 || len(arr) == 0 {
   821  		return false, ""
   822  	}
   823  
   824  	for _, v := range arr {
   825  		if (chkCase && ks.Strpos(str, v, 0) != -1) || (!chkCase && ks.Stripos(str, v, 0) != -1) {
   826  			return true, v
   827  		}
   828  	}
   829  
   830  	return false, ""
   831  }
   832  
   833  // Nl2br 将换行符转换为br标签.
   834  func (ks *LkkString) Nl2br(str string) string {
   835  	return strings.Replace(str, "\n", "<br />", -1)
   836  }
   837  
   838  // Br2nl 将br标签转换为换行符.
   839  func (ks *LkkString) Br2nl(str string) string {
   840  	// <br> , <br /> , <br/>
   841  	// <BR> , <BR /> , <BR/>
   842  
   843  	l := len(str)
   844  	buf := make([]byte, 0, l) //prealloca
   845  
   846  	for i := 0; i < l; i++ {
   847  		switch str[i] {
   848  		case 60: //<
   849  			if l >= i+3 {
   850  				/*
   851  					b = 98
   852  					B = 66
   853  					r = 82
   854  					R = 114
   855  					SPACE = 32
   856  					/ = 47
   857  					> = 62
   858  				*/
   859  
   860  				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>
   861  					buf = append(buf, bytLinefeed...)
   862  					i += 3
   863  					continue
   864  				}
   865  
   866  				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/>
   867  					buf = append(buf, bytLinefeed...)
   868  					i += 4
   869  					continue
   870  				}
   871  
   872  				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 />
   873  					buf = append(buf, bytLinefeed...)
   874  					i += 5
   875  					continue
   876  				}
   877  			}
   878  		default:
   879  			buf = append(buf, str[i])
   880  		}
   881  	}
   882  
   883  	return string(buf)
   884  }
   885  
   886  // RemoveSpace 移除字符串中的空白字符.
   887  // all为true时移除全部空白,为false时只替换连续的空白字符为一个空格.
   888  func (ks *LkkString) RemoveSpace(str string, all bool) string {
   889  	if all && str != "" {
   890  		return strings.Join(strings.Fields(str), "")
   891  	} else if str != "" {
   892  		//先将2个以上的连续空白符转为空格
   893  		str = RegWhitespaceDuplicate.ReplaceAllString(str, " ")
   894  		//再将[\t\n\f\r]等转为空格
   895  		str = RegWhitespace.ReplaceAllString(str, " ")
   896  	}
   897  
   898  	return strings.TrimSpace(str)
   899  }
   900  
   901  // StripTags 过滤html标签.
   902  func (ks *LkkString) StripTags(str string) string {
   903  	return RegHtmlTag.ReplaceAllString(str, "")
   904  }
   905  
   906  // Html2Text 将html转换为纯文本.
   907  func (ks *LkkString) Html2Text(str string) string {
   908  	domDoc := xhtml.NewTokenizer(strings.NewReader(str))
   909  	previousStartToken := domDoc.Token()
   910  	var text string
   911  loopDom:
   912  	for {
   913  		nx := domDoc.Next()
   914  		switch {
   915  		case nx == xhtml.ErrorToken:
   916  			break loopDom // End of the document
   917  		case nx == xhtml.StartTagToken:
   918  			previousStartToken = domDoc.Token()
   919  		case nx == xhtml.TextToken:
   920  			if chk, _ := ks.Dstrpos(previousStartToken.Data, TextHtmlExcludeTags, false); chk {
   921  				continue
   922  			}
   923  
   924  			text += " " + strings.TrimSpace(xhtml.UnescapeString(string(domDoc.Text())))
   925  		}
   926  	}
   927  
   928  	return ks.RemoveSpace(text, false)
   929  }
   930  
   931  // ParseStr 将URI查询字符串转换为字典.
   932  func (ks *LkkString) ParseStr(encodedString string, result map[string]interface{}) error {
   933  	// split encodedString.
   934  	if encodedString[0] == '?' {
   935  		encodedString = strings.TrimLeft(encodedString, "?")
   936  	}
   937  
   938  	parts := strings.Split(encodedString, "&")
   939  	for _, part := range parts {
   940  		pos := strings.Index(part, "=")
   941  		if pos <= 0 {
   942  			continue
   943  		}
   944  		key, err := url.QueryUnescape(part[:pos])
   945  		if err != nil {
   946  			return err
   947  		}
   948  		for key[0] == ' ' && key[1:] != "" {
   949  			key = key[1:]
   950  		}
   951  		if key == "" || key[0] == '[' {
   952  			continue
   953  		}
   954  		value, err := url.QueryUnescape(part[pos+1:])
   955  		if err != nil {
   956  			return err
   957  		}
   958  
   959  		// split into multiple keys
   960  		var keys []string
   961  		left := 0
   962  		for i, k := range key {
   963  			if k == '[' && left == 0 {
   964  				left = i
   965  			} else if k == ']' {
   966  				if left > 0 {
   967  					if len(keys) == 0 {
   968  						keys = append(keys, key[:left])
   969  					}
   970  					keys = append(keys, key[left+1:i])
   971  					left = 0
   972  					if i+1 < len(key) && key[i+1] != '[' {
   973  						break
   974  					}
   975  				}
   976  			}
   977  		}
   978  		if len(keys) == 0 {
   979  			keys = append(keys, key)
   980  		}
   981  		// first key
   982  		first := ""
   983  		for i, chr := range keys[0] {
   984  			if chr == ' ' || chr == '.' || chr == '[' {
   985  				first += "_"
   986  			} else {
   987  				first += string(chr)
   988  			}
   989  			if chr == '[' {
   990  				first += keys[0][i+1:]
   991  				break
   992  			}
   993  		}
   994  		keys[0] = first
   995  
   996  		// build nested map
   997  		if err := buildQueryMap(result, keys, value); err != nil {
   998  			return err
   999  		}
  1000  	}
  1001  
  1002  	return nil
  1003  }
  1004  
  1005  // ParseUrl 解析URL,返回其组成部分.
  1006  // component为需要返回的组成;
  1007  // -1: all; 1: scheme; 2: host; 4: port; 8: user; 16: pass; 32: path; 64: query; 128: fragment .
  1008  func (ks *LkkString) ParseUrl(str string, component int16) (map[string]string, error) {
  1009  	u, err := url.Parse(str)
  1010  	if err != nil {
  1011  		return nil, err
  1012  	}
  1013  	if component == -1 {
  1014  		component = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128
  1015  	}
  1016  	var res = make(map[string]string)
  1017  	if (component & 1) == 1 {
  1018  		res["scheme"] = u.Scheme
  1019  	}
  1020  	if (component & 2) == 2 {
  1021  		res["host"] = u.Hostname()
  1022  	}
  1023  	if (component & 4) == 4 {
  1024  		res["port"] = u.Port()
  1025  	}
  1026  	if (component & 8) == 8 {
  1027  		res["user"] = u.User.Username()
  1028  	}
  1029  	if (component & 16) == 16 {
  1030  		res["pass"], _ = u.User.Password()
  1031  	}
  1032  	if (component & 32) == 32 {
  1033  		res["path"] = u.Path
  1034  	}
  1035  	if (component & 64) == 64 {
  1036  		res["query"] = u.RawQuery
  1037  	}
  1038  	if (component & 128) == 128 {
  1039  		res["fragment"] = u.Fragment
  1040  	}
  1041  	return res, nil
  1042  }
  1043  
  1044  // UrlEncode 编码 URL 字符串.
  1045  func (ks *LkkString) UrlEncode(str string) string {
  1046  	return url.QueryEscape(str)
  1047  }
  1048  
  1049  // UrlDecode 解码已编码的 URL 字符串.
  1050  func (ks *LkkString) UrlDecode(str string) (string, error) {
  1051  	return url.QueryUnescape(str)
  1052  }
  1053  
  1054  // RawUrlEncode 按照 RFC 3986 对 URL 进行编码.
  1055  func (ks *LkkString) RawUrlEncode(str string) string {
  1056  	return strings.Replace(url.QueryEscape(str), "+", "%20", -1)
  1057  }
  1058  
  1059  // RawUrlDecode 对已编码的 URL 字符串进行解码.
  1060  func (ks *LkkString) RawUrlDecode(str string) (string, error) {
  1061  	return url.QueryUnescape(strings.Replace(str, "%20", "+", -1))
  1062  }
  1063  
  1064  // HttpBuildQuery 根据参数生成 URL-encode 之后的请求字符串.
  1065  func (ks *LkkString) HttpBuildQuery(queryData url.Values) string {
  1066  	return queryData.Encode()
  1067  }
  1068  
  1069  // FormatUrl 格式化URL.
  1070  func (ks *LkkString) FormatUrl(str string) string {
  1071  	if str != "" {
  1072  		if ks.Strpos(str, "://", 0) == -1 {
  1073  			str = "http://" + str
  1074  		}
  1075  
  1076  		// 将"\"替换为"/"
  1077  		str = strings.ReplaceAll(str, "\\", "/")
  1078  
  1079  		// 将连续的"//"或"\\"或"\/",替换为"/"
  1080  		str = RegUrlBackslashDuplicate.ReplaceAllString(str, "$1/")
  1081  	}
  1082  
  1083  	return str
  1084  }
  1085  
  1086  // GetDomain 从URL字符串中获取域名.
  1087  // 可选参数isMain,默认为false,取完整域名;为true时,取主域名(如abc.test.com取test.com).
  1088  func (ks *LkkString) GetDomain(str string, isMain ...bool) string {
  1089  	str = ks.FormatUrl(str)
  1090  	u, err := url.Parse(str)
  1091  	main := false
  1092  	if len(isMain) > 0 {
  1093  		main = isMain[0]
  1094  	}
  1095  
  1096  	if err != nil || !strings.Contains(str, ".") {
  1097  		return ""
  1098  	} else if !main {
  1099  		return u.Hostname()
  1100  	}
  1101  
  1102  	parts := strings.Split(u.Hostname(), ".")
  1103  	domain := parts[len(parts)-2] + "." + parts[len(parts)-1]
  1104  
  1105  	return domain
  1106  }
  1107  
  1108  // ClearUrlPrefix 清除URL的前缀;
  1109  // str为URL字符串,prefix为前缀,默认"/".
  1110  func (ks *LkkString) ClearUrlPrefix(str string, prefix ...string) string {
  1111  	var p string = "/"
  1112  	if len(prefix) > 0 {
  1113  		p = prefix[0]
  1114  	}
  1115  
  1116  	for p != "" && strings.HasPrefix(str, p) {
  1117  		str = str[len(p):]
  1118  	}
  1119  
  1120  	return str
  1121  }
  1122  
  1123  // ClearUrlSuffix 清除URL的后缀;
  1124  // str为URL字符串,suffix为后缀,默认"/".
  1125  func (ks *LkkString) ClearUrlSuffix(str string, suffix ...string) string {
  1126  	var s string = "/"
  1127  	if len(suffix) > 0 {
  1128  		s = suffix[0]
  1129  	}
  1130  
  1131  	for s != "" && strings.HasSuffix(str, s) {
  1132  		str = str[0 : len(str)-len(s)]
  1133  	}
  1134  
  1135  	return str
  1136  }
  1137  
  1138  // Random 生成随机字符串.
  1139  // length为长度,rtype为枚举:
  1140  // RAND_STRING_ALPHA 字母;
  1141  // RAND_STRING_NUMERIC 数值;
  1142  // RAND_STRING_ALPHANUM 字母+数值;
  1143  // RAND_STRING_SPECIAL 字母+数值+特殊字符;
  1144  // RAND_STRING_CHINESE 仅中文.
  1145  func (ks *LkkString) Random(length uint8, rtype LkkRandString) string {
  1146  	if length == 0 {
  1147  		return ""
  1148  	}
  1149  
  1150  	var letter []rune
  1151  	alphas := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  1152  	numbers := "0123456789"
  1153  	specials := "~!@#$%^&*()_+{}:|<>?`-=;,."
  1154  
  1155  	rand.Seed(time.Now().UTC().UnixNano())
  1156  
  1157  	switch rtype {
  1158  	case RAND_STRING_ALPHA:
  1159  		letter = []rune(alphas)
  1160  	case RAND_STRING_NUMERIC:
  1161  		letter = []rune(numbers)
  1162  	case RAND_STRING_ALPHANUM:
  1163  		letter = []rune(alphas + numbers)
  1164  	case RAND_STRING_SPECIAL:
  1165  		letter = []rune(alphas + numbers + specials)
  1166  	case RAND_STRING_CHINESE:
  1167  		letter = CommonChinese
  1168  	default:
  1169  		letter = []rune(alphas)
  1170  	}
  1171  
  1172  	res := make([]rune, length)
  1173  	for i := range res {
  1174  		res[i] = letter[rand.Intn(len(letter))]
  1175  	}
  1176  
  1177  	return string(res)
  1178  }
  1179  
  1180  // DetectEncoding 匹配字符编码,TODO.
  1181  func (ks *LkkString) DetectEncoding(str string) (res string) {
  1182  	//TODO 检查字符编码
  1183  	return
  1184  }
  1185  
  1186  // Ucfirst 将字符串的第一个字符转换为大写.
  1187  func (ks *LkkString) Ucfirst(str string) string {
  1188  	for _, v := range str {
  1189  		u := string(unicode.ToUpper(v))
  1190  		return u + str[len(u):]
  1191  	}
  1192  	return ""
  1193  }
  1194  
  1195  // Lcfirst 将字符串的第一个字符转换为小写.
  1196  func (ks *LkkString) Lcfirst(str string) string {
  1197  	for _, v := range str {
  1198  		u := string(unicode.ToLower(v))
  1199  		return u + str[len(u):]
  1200  	}
  1201  	return ""
  1202  }
  1203  
  1204  // Ucwords 将字符串中每个词的首字母转换为大写.
  1205  func (ks *LkkString) Ucwords(str string) string {
  1206  	caser := cases.Title(language.English)
  1207  	return caser.String(str)
  1208  }
  1209  
  1210  // Lcwords 将字符串中每个词的首字母转换为小写.
  1211  func (ks *LkkString) Lcwords(str string) string {
  1212  	buf := &bytes.Buffer{}
  1213  	lastIsSpace := true
  1214  	for _, r := range str {
  1215  		if unicode.IsLetter(r) {
  1216  			if lastIsSpace {
  1217  				r = unicode.ToLower(r)
  1218  			}
  1219  
  1220  			lastIsSpace = false
  1221  		} else {
  1222  			lastIsSpace = false
  1223  			if unicode.IsSpace(r) || unicode.IsPunct(r) || unicode.IsSymbol(r) || unicode.IsMark(r) {
  1224  				lastIsSpace = true
  1225  			}
  1226  		}
  1227  
  1228  		buf.WriteRune(r)
  1229  	}
  1230  
  1231  	return buf.String()
  1232  }
  1233  
  1234  // Substr 截取字符串str的子串.
  1235  // start 为起始位置.若值是负数,返回的结果将从 str 结尾处向前数第 abs(start) 个字符开始.
  1236  // length 为截取的长度.若值时负数, str 末尾处的 abs(length) 个字符将会被省略.
  1237  // start/length的绝对值必须<=原字符串长度.
  1238  func (ks *LkkString) Substr(str string, start int, length ...int) string {
  1239  	total := len(str)
  1240  	if total == 0 {
  1241  		return ""
  1242  	}
  1243  
  1244  	var sublen, end int
  1245  	max := total //最大的结束位置
  1246  
  1247  	if len(length) == 0 {
  1248  		sublen = total
  1249  	} else {
  1250  		sublen = length[0]
  1251  	}
  1252  
  1253  	if start < 0 {
  1254  		start = total + start
  1255  	}
  1256  
  1257  	if sublen < 0 {
  1258  		sublen = total + sublen
  1259  		if sublen > 0 {
  1260  			max = sublen
  1261  		}
  1262  	}
  1263  
  1264  	if start < 0 || sublen <= 0 || start >= max {
  1265  		return ""
  1266  	}
  1267  
  1268  	end = start + sublen
  1269  	if end > max {
  1270  		end = max
  1271  	}
  1272  
  1273  	return str[start:end]
  1274  }
  1275  
  1276  // MbSubstr 返回(宽字符)字符串str的子串.
  1277  // start 为起始位置.若值是负数,返回的结果将从 str 结尾处向前数第 abs(start) 个字符开始.
  1278  // length 为截取的长度.若值时负数, str 末尾处的 abs(length) 个字符将会被省略.
  1279  // start/length的绝对值必须<=原字符串长度.
  1280  func (ks *LkkString) MbSubstr(str string, start int, length ...int) string {
  1281  	if len(str) == 0 {
  1282  		return ""
  1283  	}
  1284  
  1285  	runes := []rune(str)
  1286  	total := len(runes)
  1287  
  1288  	var sublen, end int
  1289  	max := total //最大的结束位置
  1290  
  1291  	if len(length) == 0 {
  1292  		sublen = total
  1293  	} else {
  1294  		sublen = length[0]
  1295  	}
  1296  
  1297  	if start < 0 {
  1298  		start = total + start
  1299  	}
  1300  
  1301  	if sublen < 0 {
  1302  		sublen = total + sublen
  1303  		if sublen > 0 {
  1304  			max = sublen
  1305  		}
  1306  	}
  1307  
  1308  	if start < 0 || sublen <= 0 || start >= max {
  1309  		return ""
  1310  	}
  1311  
  1312  	end = start + sublen
  1313  	if end > max {
  1314  		end = max
  1315  	}
  1316  
  1317  	return string(runes[start:end])
  1318  }
  1319  
  1320  // SubstrCount 计算子串substr在字符串str中出现的次数,区分大小写.
  1321  func (ks *LkkString) SubstrCount(str, substr string) int {
  1322  	return strings.Count(str, substr)
  1323  }
  1324  
  1325  // SubstriCount 计算子串substr在字符串str中出现的次数,忽略大小写.
  1326  func (ks *LkkString) SubstriCount(str, substr string) int {
  1327  	return strings.Count(strings.ToLower(str), strings.ToLower(substr))
  1328  }
  1329  
  1330  // Reverse 反转字符串.
  1331  func (ks *LkkString) Reverse(str string) string {
  1332  	n := len(str)
  1333  	runes := make([]rune, n)
  1334  	for _, r := range str {
  1335  		n--
  1336  		runes[n] = r
  1337  	}
  1338  	return string(runes[n:])
  1339  }
  1340  
  1341  // ChunkSplit 将字符串分割成小块.str为要分割的字符,chunklen为分割的尺寸,end为行尾序列符号.
  1342  func (ks *LkkString) ChunkSplit(str string, chunklen uint, end string) string {
  1343  	if end == "" {
  1344  		return str
  1345  	}
  1346  
  1347  	runes, erunes := []rune(str), []rune(end)
  1348  	length := uint(len(runes))
  1349  	if length <= 1 || length < chunklen {
  1350  		return str + end
  1351  	}
  1352  	ns := make([]rune, 0, len(runes)+len(erunes))
  1353  	var i uint
  1354  	for i = 0; i < length; i += chunklen {
  1355  		if i+chunklen > length {
  1356  			ns = append(ns, runes[i:]...)
  1357  		} else {
  1358  			ns = append(ns, runes[i:i+chunklen]...)
  1359  		}
  1360  		ns = append(ns, erunes...)
  1361  	}
  1362  	return string(ns)
  1363  }
  1364  
  1365  // Strlen 获取字符串长度.
  1366  func (ks *LkkString) Strlen(str string) int {
  1367  	return len(str)
  1368  }
  1369  
  1370  // MbStrlen 获取宽字符串的长度,多字节的字符被计为 1.
  1371  func (ks *LkkString) MbStrlen(str string) int {
  1372  	return utf8.RuneCountInString(str)
  1373  }
  1374  
  1375  // Shuffle 随机打乱字符串.
  1376  func (ks *LkkString) Shuffle(str string) string {
  1377  	if str == "" {
  1378  		return str
  1379  	}
  1380  
  1381  	runes := []rune(str)
  1382  	index := 0
  1383  
  1384  	for i := len(runes) - 1; i > 0; i-- {
  1385  		index = rand.Intn(i + 1)
  1386  
  1387  		if i != index {
  1388  			runes[i], runes[index] = runes[index], runes[i]
  1389  		}
  1390  	}
  1391  
  1392  	return string(runes)
  1393  }
  1394  
  1395  // Ord 将首字符转换为rune(ASCII值).
  1396  // 注意:当字符串为空时返回65533.
  1397  func (ks *LkkString) Ord(char string) rune {
  1398  	r, _ := utf8.DecodeRune([]byte(char))
  1399  	return r
  1400  }
  1401  
  1402  // Chr 返回相对应于 ASCII 所指定的单个字符.
  1403  func (ks *LkkString) Chr(chr uint) string {
  1404  	return string(rune(chr))
  1405  }
  1406  
  1407  // Serialize 对变量进行序列化.
  1408  func (ks *LkkString) Serialize(val interface{}) ([]byte, error) {
  1409  	buf := bytes.Buffer{}
  1410  	enc := gob.NewEncoder(&buf)
  1411  	gob.Register(val)
  1412  
  1413  	err := enc.Encode(&val)
  1414  	if err != nil {
  1415  		return nil, err
  1416  	}
  1417  
  1418  	return buf.Bytes(), nil
  1419  }
  1420  
  1421  // UnSerialize 对字符串进行反序列化.
  1422  // 其中register注册对象,其类型必须和Serialize的一致.
  1423  func (ks *LkkString) UnSerialize(data []byte, register ...interface{}) (val interface{}, err error) {
  1424  	for _, v := range register {
  1425  		gob.Register(v)
  1426  		break
  1427  	}
  1428  
  1429  	buf := bytes.NewBuffer(data)
  1430  	dec := gob.NewDecoder(buf)
  1431  	err = dec.Decode(&val)
  1432  	return
  1433  }
  1434  
  1435  // Quotemeta 转义元字符集,包括 . \ + * ? [ ^ ] ( $ )等.
  1436  func (ks *LkkString) Quotemeta(str string) string {
  1437  	var buf bytes.Buffer
  1438  	for _, char := range str {
  1439  		switch char {
  1440  		case '.', '+', '\\', '(', '$', ')', '[', '^', ']', '*', '?':
  1441  			buf.WriteRune('\\')
  1442  		}
  1443  		buf.WriteRune(char)
  1444  	}
  1445  	return buf.String()
  1446  }
  1447  
  1448  // Htmlentities 将字符转换为 HTML 转义字符.
  1449  func (ks *LkkString) Htmlentities(str string) string {
  1450  	return html.EscapeString(str)
  1451  }
  1452  
  1453  // HtmlentityDecode 将HTML实体转换为它们对应的字符.
  1454  func (ks *LkkString) HtmlentityDecode(str string) string {
  1455  	return html.UnescapeString(str)
  1456  }
  1457  
  1458  // Crc32 计算一个字符串的 crc32 多项式.
  1459  func (ks *LkkString) Crc32(str string) uint32 {
  1460  	return crc32.ChecksumIEEE([]byte(str))
  1461  }
  1462  
  1463  // SimilarText 计算两个字符串的相似度;返回在两个字符串中匹配字符的数目,以及相似程度百分数.
  1464  func (ks *LkkString) SimilarText(first, second string) (res int, percent float64) {
  1465  	l1, l2 := len(first), len(second)
  1466  	if l1+l2 == 0 {
  1467  		return 0, 0.0
  1468  	}
  1469  
  1470  	res = similarText(first, second, l1, l2)
  1471  	percent = float64(res*200) / float64(l1+l2)
  1472  
  1473  	return res, percent
  1474  }
  1475  
  1476  // Explode 字符串分割.delimiters为分隔符,可选,支持多个.
  1477  func (ks *LkkString) Explode(str string, delimiters ...string) (res []string) {
  1478  	if str == "" {
  1479  		return
  1480  	}
  1481  
  1482  	dLen := len(delimiters)
  1483  	if dLen == 0 {
  1484  		res = append(res, str)
  1485  	} else if dLen > 1 {
  1486  		var sl []string
  1487  		for _, v := range delimiters {
  1488  			if v != "" {
  1489  				sl = append(sl, v, KDelimiter)
  1490  			}
  1491  		}
  1492  		str = strings.NewReplacer(sl...).Replace(str)
  1493  		res = strings.Split(str, KDelimiter)
  1494  	} else {
  1495  		res = strings.Split(str, delimiters[0])
  1496  	}
  1497  
  1498  	return
  1499  }
  1500  
  1501  // Uniqid 获取一个带前缀的唯一ID(24位).
  1502  // prefix 为前缀字符串.
  1503  func (ks *LkkString) Uniqid(prefix string) string {
  1504  	buf := make([]byte, 12)
  1505  	_, _ = crand.Read(buf)
  1506  
  1507  	return fmt.Sprintf("%s%08x%16x",
  1508  		prefix,
  1509  		buf[0:4],
  1510  		buf[4:12])
  1511  }
  1512  
  1513  // UuidV4 获取36位UUID(Version4).
  1514  func (ks *LkkString) UuidV4() (string, error) {
  1515  	buf := make([]byte, 16)
  1516  	_, err := crand.Read(buf)
  1517  
  1518  	return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
  1519  		buf[0:4],
  1520  		buf[4:6],
  1521  		buf[6:8],
  1522  		buf[8:10],
  1523  		buf[10:16]), err
  1524  }
  1525  
  1526  // VersionCompare 对比两个版本号字符串.
  1527  // operator允许的操作符有: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne .
  1528  // 特定的版本字符串,将会用以下顺序处理:
  1529  // 无 < dev < alpha = a < beta = b < RC = rc < # < pl = p < ga < release = r
  1530  // 用法:
  1531  // VersionCompare("1.2.3-alpha", "1.2.3RC7", '>=') ;
  1532  // VersionCompare("1.2.3-beta", "1.2.3pl", 'lt') ;
  1533  // VersionCompare("1.1_dev", "1.2any", 'eq') .
  1534  func (ks *LkkString) VersionCompare(version1, version2, operator string) (bool, error) {
  1535  	var canonicalize func(string) string
  1536  	var vcompare func(string, string) int
  1537  	var special func(string, string) int
  1538  
  1539  	// canonicalize 规范化转换
  1540  	canonicalize = func(version string) string {
  1541  		ver := []byte(version)
  1542  		l := len(ver)
  1543  		var buf = make([]byte, l*2)
  1544  		j := 0
  1545  		for i, v := range ver {
  1546  			next := uint8(0)
  1547  			if i+1 < l { // Have the next one
  1548  				next = ver[i+1]
  1549  			}
  1550  			if v == '-' || v == '_' || v == '+' { // replace '-', '_', '+' to '.'
  1551  				if j > 0 && buf[j-1] != '.' {
  1552  					buf[j] = '.'
  1553  					j++
  1554  				}
  1555  			} else if (next > 0) &&
  1556  				(!(next >= '0' && next <= '9') && (v >= '0' && v <= '9')) ||
  1557  				(!(v >= '0' && v <= '9') && (next >= '0' && next <= '9')) { // Insert '.' before and after a non-digit
  1558  				buf[j] = v
  1559  				j++
  1560  				if v != '.' && next != '.' {
  1561  					buf[j] = '.'
  1562  					j++
  1563  				}
  1564  				continue
  1565  			} else if !((v >= '0' && v <= '9') ||
  1566  				(v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z')) { // Non-letters and numbers
  1567  				if j > 0 && buf[j-1] != '.' {
  1568  					buf[j] = '.'
  1569  					j++
  1570  				}
  1571  			} else {
  1572  				buf[j] = v
  1573  				j++
  1574  			}
  1575  		}
  1576  
  1577  		return string(buf[:j])
  1578  	}
  1579  
  1580  	// version compare
  1581  	// 在第一个版本低于第二个时,vcompare() 返回 -1;如果两者相等,返回 0;第二个版本更低时则返回 1.
  1582  	vcompare = func(origV1, origV2 string) int {
  1583  		if origV1 == "" || origV2 == "" {
  1584  			if origV1 == "" && origV2 == "" {
  1585  				return 0
  1586  			}
  1587  			if origV1 == "" {
  1588  				return -1
  1589  			}
  1590  			return 1
  1591  		}
  1592  
  1593  		ver1, ver2, compare := canonicalize(origV1), canonicalize(origV2), 0
  1594  		n1, n2 := 0, 0
  1595  		for {
  1596  			p1, p2 := "", ""
  1597  			n1 = strings.IndexByte(ver1, '.')
  1598  			if n1 == -1 {
  1599  				p1, ver1 = ver1[:], ""
  1600  			} else {
  1601  				p1, ver1 = ver1[:n1], ver1[n1+1:]
  1602  			}
  1603  			n2 = strings.IndexByte(ver2, '.')
  1604  			if n2 == -1 {
  1605  				p2, ver2 = ver2, ""
  1606  			} else {
  1607  				p2, ver2 = ver2[:n2], ver2[n2+1:]
  1608  			}
  1609  
  1610  			if p1 == "" || p2 == "" {
  1611  				break
  1612  			}
  1613  
  1614  			if (p1[0] >= '0' && p1[0] <= '9') && (p2[0] >= '0' && p2[0] <= '9') { // all is digit
  1615  				l1, _ := strconv.Atoi(p1)
  1616  				l2, _ := strconv.Atoi(p2)
  1617  				if l1 > l2 {
  1618  					compare = 1
  1619  				} else if l1 == l2 {
  1620  					compare = 0
  1621  				} else {
  1622  					compare = -1
  1623  				}
  1624  			} else {
  1625  				compare = special(p1, p2)
  1626  			}
  1627  			if compare != 0 || n1 == -1 || n2 == -1 {
  1628  				break
  1629  			}
  1630  		}
  1631  
  1632  		return compare
  1633  	}
  1634  
  1635  	// compare special version forms 特殊版本号
  1636  	special = func(form1, form2 string) int {
  1637  		found1, found2 := -1, -1
  1638  		// (Any string not found) < dev < alpha = a < beta = b < RC = rc < # < pl = p < ga < release = r
  1639  		forms := map[string]int{
  1640  			"dev":     0,
  1641  			"alpha":   1,
  1642  			"a":       1,
  1643  			"beta":    2,
  1644  			"b":       2,
  1645  			"RC":      3,
  1646  			"rc":      3,
  1647  			"#":       4,
  1648  			"pl":      5,
  1649  			"p":       5,
  1650  			"ga":      6,
  1651  			"release": 7,
  1652  			"r":       7,
  1653  		}
  1654  
  1655  		for name, order := range forms {
  1656  			if form1 == name {
  1657  				found1 = order
  1658  				break
  1659  			}
  1660  		}
  1661  		for name, order := range forms {
  1662  			if form2 == name {
  1663  				found2 = order
  1664  				break
  1665  			}
  1666  		}
  1667  
  1668  		if found1 == found2 {
  1669  			if found1 == -1 {
  1670  				return strings.Compare(form1, form2)
  1671  			}
  1672  			return 0
  1673  		} else if found1 > found2 {
  1674  			return 1
  1675  		} else {
  1676  			return -1
  1677  		}
  1678  	}
  1679  
  1680  	compare := vcompare(version1, version2)
  1681  	// 在第一个版本低于第二个时,vcompare() 返回 -1;如果两者相等,返回 0;第二个版本更低时则返回 1.
  1682  	switch operator {
  1683  	case "<", "lt":
  1684  		return compare == -1, nil
  1685  	case "<=", "le":
  1686  		return compare != 1, nil
  1687  	case ">", "gt":
  1688  		return compare == 1, nil
  1689  	case ">=", "ge":
  1690  		return compare != -1, nil
  1691  	case "==", "=", "eq":
  1692  		return compare == 0, nil
  1693  	case "!=", "<>", "ne":
  1694  		return compare != 0, nil
  1695  	default:
  1696  		return false, errors.New("[VersionCompare]`operator: invalid")
  1697  	}
  1698  }
  1699  
  1700  // ToCamelCase 转为驼峰写法.
  1701  // 去掉包括下划线"_"和横杠"-".
  1702  func (ks *LkkString) ToCamelCase(str string) string {
  1703  	if len(str) == 0 {
  1704  		return ""
  1705  	}
  1706  
  1707  	buf := &bytes.Buffer{}
  1708  	var r0, r1 rune
  1709  	var size int
  1710  
  1711  	// leading connector will appear in output.
  1712  	for len(str) > 0 {
  1713  		r0, size = utf8.DecodeRuneInString(str)
  1714  		str = str[size:]
  1715  
  1716  		if !isCaseConnector(r0) {
  1717  			r0 = unicode.ToUpper(r0)
  1718  			break
  1719  		}
  1720  
  1721  		buf.WriteRune(r0)
  1722  	}
  1723  
  1724  	for len(str) > 0 {
  1725  		r1 = r0
  1726  		r0, size = utf8.DecodeRuneInString(str)
  1727  		str = str[size:]
  1728  
  1729  		if isCaseConnector(r0) && isCaseConnector(r1) {
  1730  			buf.WriteRune(r1)
  1731  			continue
  1732  		}
  1733  
  1734  		if isCaseConnector(r1) {
  1735  			r0 = unicode.ToUpper(r0)
  1736  		} else if unicode.IsLower(r1) && unicode.IsUpper(r0) {
  1737  			buf.WriteRune(r1)
  1738  		} else if unicode.IsUpper(r1) && unicode.IsLower(r0) {
  1739  			buf.WriteRune(r1)
  1740  		} else {
  1741  			r0 = unicode.ToLower(r0)
  1742  			buf.WriteRune(r1)
  1743  		}
  1744  	}
  1745  
  1746  	buf.WriteRune(r0)
  1747  	return buf.String()
  1748  }
  1749  
  1750  // ToSnakeCase 转为蛇形写法.
  1751  // 使用下划线"_"连接.
  1752  func (ks *LkkString) ToSnakeCase(str string) string {
  1753  	return camelCaseToLowerCase(str, '_')
  1754  }
  1755  
  1756  // ToSnakeCase 转为串形写法.
  1757  // 使用横杠"-"连接.
  1758  func (ks *LkkString) ToKebabCase(str string) string {
  1759  	return camelCaseToLowerCase(str, '-')
  1760  }
  1761  
  1762  // RemoveBefore 移除before之前的字符串;
  1763  // include为是否移除包括before本身;
  1764  // ignoreCase为是否忽略大小写.
  1765  func (ks *LkkString) RemoveBefore(str, before string, include, ignoreCase bool) string {
  1766  	i := ks.Index(str, before, ignoreCase)
  1767  	if i > 0 {
  1768  		if include {
  1769  			str = str[i+len(before):]
  1770  		} else {
  1771  			str = str[i:]
  1772  		}
  1773  	}
  1774  	return str
  1775  }
  1776  
  1777  // RemoveAfter 移除after之后的字符串;
  1778  // include为是否移除包括after本身;
  1779  // ignoreCase为是否忽略大小写.
  1780  func (ks *LkkString) RemoveAfter(str, after string, include, ignoreCase bool) string {
  1781  	i := ks.Index(str, after, ignoreCase)
  1782  	if i > 0 {
  1783  		if include {
  1784  			str = str[0:i]
  1785  		} else {
  1786  			str = str[0 : i+len(after)]
  1787  		}
  1788  	}
  1789  	return str
  1790  }
  1791  
  1792  // DBC2SBC 半角转全角.
  1793  func (ks *LkkString) DBC2SBC(s string) string {
  1794  	return width.Widen.String(s)
  1795  }
  1796  
  1797  // SBC2DBC 全角转半角.
  1798  func (ks *LkkString) SBC2DBC(s string) string {
  1799  	return width.Narrow.String(s)
  1800  }
  1801  
  1802  // Levenshtein 计算两个字符串之间的编辑距离,返回值越小字符串越相似.
  1803  // 注意字符串最大长度为255.
  1804  func (ks *LkkString) Levenshtein(a, b string) int {
  1805  	la := len(a)
  1806  	lb := len(b)
  1807  
  1808  	if a == b {
  1809  		return 0
  1810  	} else if la > 255 || lb > 255 {
  1811  		return -1
  1812  	}
  1813  
  1814  	d := make([]int, la+1)
  1815  	var lastdiag, olddiag, temp int
  1816  	for i := 1; i <= la; i++ {
  1817  		d[i] = i
  1818  	}
  1819  	for i := 1; i <= lb; i++ {
  1820  		d[0] = i
  1821  		lastdiag = i - 1
  1822  		for j := 1; j <= la; j++ {
  1823  			olddiag = d[j]
  1824  			min := d[j] + 1
  1825  			if (d[j-1] + 1) < min {
  1826  				min = d[j-1] + 1
  1827  			}
  1828  			if (a)[j-1] == (b)[i-1] {
  1829  				temp = 0
  1830  			} else {
  1831  				temp = 1
  1832  			}
  1833  			if (lastdiag + temp) < min {
  1834  				min = lastdiag + temp
  1835  			}
  1836  			d[j] = min
  1837  			lastdiag = olddiag
  1838  		}
  1839  	}
  1840  	return d[la]
  1841  }
  1842  
  1843  // ClosestWord 获取与原字符串相似度最高的字符串,以及它们的编辑距离.
  1844  // word为原字符串,searchs为待查找的字符串数组.
  1845  func (ks *LkkString) ClosestWord(word string, searchs []string) (string, int) {
  1846  	distance := 10000
  1847  	res := ""
  1848  	for _, search := range searchs {
  1849  		newVal := ks.Levenshtein(word, search)
  1850  		if newVal == 0 {
  1851  			distance = 0
  1852  			res = search
  1853  			break
  1854  		}
  1855  
  1856  		if newVal < distance {
  1857  			distance = newVal
  1858  			res = search
  1859  		}
  1860  	}
  1861  
  1862  	return res, distance
  1863  }
  1864  
  1865  // Utf8ToBig5 UTF-8转BIG5编码.
  1866  func (ks *LkkString) Utf8ToBig5(s []byte) ([]byte, error) {
  1867  	reader := transform.NewReader(bytes.NewReader(s), traditionalchinese.Big5.NewEncoder())
  1868  	d, e := ioutil.ReadAll(reader)
  1869  	return d, e
  1870  }
  1871  
  1872  // Big5ToUtf8 BIG5转UTF-8编码.
  1873  func (ks *LkkString) Big5ToUtf8(s []byte) ([]byte, error) {
  1874  	reader := transform.NewReader(bytes.NewReader(s), traditionalchinese.Big5.NewDecoder())
  1875  	d, e := ioutil.ReadAll(reader)
  1876  	return d, e
  1877  }
  1878  
  1879  // FirstLetter 获取字符串首字母.
  1880  func (ks *LkkString) FirstLetter(str string) string {
  1881  	if str != "" {
  1882  		// 获取字符串第一个字符
  1883  		_, size := utf8.DecodeRuneInString(str)
  1884  		firstChar := str[:size]
  1885  
  1886  		if ks.IsLetters(firstChar) {
  1887  			return firstChar
  1888  		} else if ks.IsChinese(firstChar) {
  1889  			// Utf8 转 GBK2312
  1890  			firstCharGbk, _ := ks.Utf8ToGbk([]byte(firstChar))
  1891  
  1892  			// 获取第一个字符的16进制
  1893  			firstCharHex := hex.EncodeToString(firstCharGbk)
  1894  
  1895  			// 16进制转十进制
  1896  			firstCharDec, _ := strconv.ParseInt(firstCharHex, 16, 0)
  1897  
  1898  			// 十进制落在GB 2312的某个拼音区间即为某个字母
  1899  			firstCharDecimalRelative := firstCharDec - 65536
  1900  			if firstCharDecimalRelative >= -20319 && firstCharDecimalRelative <= -20284 {
  1901  				return "A"
  1902  			}
  1903  			if firstCharDecimalRelative >= -20283 && firstCharDecimalRelative <= -19776 {
  1904  				return "B"
  1905  			}
  1906  			if firstCharDecimalRelative >= -19775 && firstCharDecimalRelative <= -19219 {
  1907  				return "C"
  1908  			}
  1909  			if firstCharDecimalRelative >= -19218 && firstCharDecimalRelative <= -18711 {
  1910  				return "D"
  1911  			}
  1912  			if firstCharDecimalRelative >= -18710 && firstCharDecimalRelative <= -18527 {
  1913  				return "E"
  1914  			}
  1915  			if firstCharDecimalRelative >= -18526 && firstCharDecimalRelative <= -18240 {
  1916  				return "F"
  1917  			}
  1918  			if firstCharDecimalRelative >= -18239 && firstCharDecimalRelative <= -17923 {
  1919  				return "G"
  1920  			}
  1921  			if firstCharDecimalRelative >= -17922 && firstCharDecimalRelative <= -17418 {
  1922  				return "H"
  1923  			}
  1924  			if firstCharDecimalRelative >= -17417 && firstCharDecimalRelative <= -16475 {
  1925  				return "J"
  1926  			}
  1927  			if firstCharDecimalRelative >= -16474 && firstCharDecimalRelative <= -16213 {
  1928  				return "K"
  1929  			}
  1930  			if firstCharDecimalRelative >= -16212 && firstCharDecimalRelative <= -15641 {
  1931  				return "L"
  1932  			}
  1933  			if firstCharDecimalRelative >= -15640 && firstCharDecimalRelative <= -15166 {
  1934  				return "M"
  1935  			}
  1936  			if firstCharDecimalRelative >= -15165 && firstCharDecimalRelative <= -14923 {
  1937  				return "N"
  1938  			}
  1939  			if firstCharDecimalRelative >= -14922 && firstCharDecimalRelative <= -14915 {
  1940  				return "O"
  1941  			}
  1942  			if firstCharDecimalRelative >= -14914 && firstCharDecimalRelative <= -14631 {
  1943  				return "P"
  1944  			}
  1945  			if firstCharDecimalRelative >= -14630 && firstCharDecimalRelative <= -14150 {
  1946  				return "Q"
  1947  			}
  1948  			if firstCharDecimalRelative >= -14149 && firstCharDecimalRelative <= -14091 {
  1949  				return "R"
  1950  			}
  1951  			if firstCharDecimalRelative >= -14090 && firstCharDecimalRelative <= -13319 {
  1952  				return "S"
  1953  			}
  1954  			if firstCharDecimalRelative >= -13318 && firstCharDecimalRelative <= -12839 {
  1955  				return "T"
  1956  			}
  1957  			if firstCharDecimalRelative >= -12838 && firstCharDecimalRelative <= -12557 {
  1958  				return "W"
  1959  			}
  1960  			if firstCharDecimalRelative >= -12556 && firstCharDecimalRelative <= -11848 {
  1961  				return "X"
  1962  			}
  1963  			if firstCharDecimalRelative >= -11847 && firstCharDecimalRelative <= -11056 {
  1964  				return "Y"
  1965  			}
  1966  			if firstCharDecimalRelative >= -11055 && firstCharDecimalRelative <= -10247 {
  1967  				return "Z"
  1968  			}
  1969  		}
  1970  	}
  1971  
  1972  	return ""
  1973  }
  1974  
  1975  // HideCard 隐藏证件号码.
  1976  func (ks *LkkString) HideCard(card string) string {
  1977  	res := "******"
  1978  	leng := len(card)
  1979  	if leng > 4 && leng <= 10 {
  1980  		res = card[0:4] + "******"
  1981  	} else if leng > 10 {
  1982  		res = card[0:4] + "******" + card[(leng-4):leng]
  1983  	}
  1984  
  1985  	return res
  1986  }
  1987  
  1988  // HideMobile 隐藏手机号.
  1989  func (ks *LkkString) HideMobile(mobile string) string {
  1990  	res := "***"
  1991  	leng := len(mobile)
  1992  	if leng > 7 {
  1993  		res = mobile[0:3] + "****" + mobile[leng-3:leng]
  1994  	}
  1995  
  1996  	return res
  1997  }
  1998  
  1999  // HideTrueName 隐藏真实名称(如姓名、账号、公司等).
  2000  func (ks *LkkString) HideTrueName(name string) string {
  2001  	res := "**"
  2002  	if name != "" {
  2003  		runs := []rune(name)
  2004  		leng := len(runs)
  2005  		if leng <= 3 {
  2006  			res = string(runs[0:1]) + res
  2007  		} else if leng < 5 {
  2008  			res = string(runs[0:2]) + res
  2009  		} else if leng < 10 {
  2010  			res = string(runs[0:2]) + "***" + string(runs[leng-2:leng])
  2011  		} else if leng < 16 {
  2012  			res = string(runs[0:3]) + "****" + string(runs[leng-3:leng])
  2013  		} else {
  2014  			res = string(runs[0:4]) + "*****" + string(runs[leng-4:leng])
  2015  		}
  2016  	}
  2017  
  2018  	return res
  2019  }
  2020  
  2021  // CountBase64Byte 粗略统计base64字符串大小,字节.
  2022  func (ks *LkkString) CountBase64Byte(str string) (res int) {
  2023  	pos := strings.Index(str, ",")
  2024  	if pos > 10 {
  2025  		img := strings.Replace(str[pos:], "=", "", -1)
  2026  		res = int(float64(len(img)) * float64(3.0/4.0))
  2027  	}
  2028  
  2029  	return
  2030  }
  2031  
  2032  // Strpad 使用fill填充str字符串到指定长度max.
  2033  // ptype为填充类型,枚举值(PAD_LEFT,PAD_RIGHT,PAD_BOTH).
  2034  func (ks *LkkString) Strpad(str string, fill string, max int, ptype LkkPadType) string {
  2035  	runeStr := []rune(str)
  2036  	runeStrLen := len(runeStr)
  2037  	if runeStrLen >= max || max < 1 || len(fill) == 0 {
  2038  		return str
  2039  	}
  2040  
  2041  	var leftsize int
  2042  	var rightsize int
  2043  
  2044  	switch ptype {
  2045  	case PAD_BOTH:
  2046  		rlsize := float64(max-runeStrLen) / 2
  2047  		leftsize = int(rlsize)
  2048  		rightsize = int(rlsize + math.Copysign(0.5, rlsize))
  2049  	case PAD_LEFT:
  2050  		leftsize = max - runeStrLen
  2051  	case PAD_RIGHT:
  2052  		rightsize = max - runeStrLen
  2053  	}
  2054  
  2055  	buf := make([]rune, 0, max)
  2056  
  2057  	if ptype == PAD_LEFT || ptype == PAD_BOTH {
  2058  		for i := 0; i < leftsize; {
  2059  			for _, v := range []rune(fill) {
  2060  				buf = append(buf, v)
  2061  				if i >= leftsize-1 {
  2062  					i = leftsize
  2063  					break
  2064  				} else {
  2065  					i++
  2066  				}
  2067  			}
  2068  		}
  2069  	}
  2070  
  2071  	buf = append(buf, runeStr...)
  2072  
  2073  	if ptype == PAD_RIGHT || ptype == PAD_BOTH {
  2074  		for i := 0; i < rightsize; {
  2075  			for _, v := range []rune(fill) {
  2076  				buf = append(buf, v)
  2077  				if i >= rightsize-1 {
  2078  					i = rightsize
  2079  					break
  2080  				} else {
  2081  					i++
  2082  				}
  2083  			}
  2084  		}
  2085  	}
  2086  
  2087  	return string(buf)
  2088  }
  2089  
  2090  // StrpadLeft 字符串左侧填充,请参考Strpad.
  2091  func (ks *LkkString) StrpadLeft(str string, fill string, max int) string {
  2092  	return ks.Strpad(str, fill, max, PAD_LEFT)
  2093  }
  2094  
  2095  // StrpadRight 字符串右侧填充,请参考Strpad.
  2096  func (ks *LkkString) StrpadRight(str string, fill string, max int) string {
  2097  	return ks.Strpad(str, fill, max, PAD_RIGHT)
  2098  }
  2099  
  2100  // StrpadBoth 字符串两侧填充,请参考Strpad.
  2101  func (ks *LkkString) StrpadBoth(str string, fill string, max int) string {
  2102  	return ks.Strpad(str, fill, max, PAD_BOTH)
  2103  }
  2104  
  2105  // CountWords 统计字符串中单词的使用情况.
  2106  // 返回结果:单词总数;和一个字典,包含每个单词的单独统计.
  2107  // 因为没有分词,对中文尚未很好支持.
  2108  func (ks *LkkString) CountWords(str string) (int, map[string]int) {
  2109  	//过滤标点符号
  2110  	var buffer bytes.Buffer
  2111  	for _, r := range str {
  2112  		if unicode.IsPunct(r) || unicode.IsSymbol(r) || unicode.IsMark(r) {
  2113  			buffer.WriteRune(' ')
  2114  		} else {
  2115  			buffer.WriteRune(r)
  2116  		}
  2117  	}
  2118  
  2119  	var total int
  2120  	mp := make(map[string]int)
  2121  	words := strings.Fields(buffer.String())
  2122  	for _, word := range words {
  2123  		mp[word] += 1
  2124  		total++
  2125  	}
  2126  
  2127  	return total, mp
  2128  }
  2129  
  2130  // HasEmoji 字符串是否含有表情符.
  2131  func (ks *LkkString) HasEmoji(str string) bool {
  2132  	return str != "" && RegEmoji.MatchString(str)
  2133  }
  2134  
  2135  // RemoveEmoji 移除字符串中的表情符(使用正则,效率较低).
  2136  func (ks *LkkString) RemoveEmoji(str string) string {
  2137  	return RegEmoji.ReplaceAllString(str, "")
  2138  }
  2139  
  2140  // Gravatar 获取Gravatar头像地址.
  2141  // email为邮箱;size为头像尺寸像素.
  2142  func (ks *LkkString) Gravatar(email string, size uint16) string {
  2143  	h := md5.New()
  2144  	_, _ = io.WriteString(h, email)
  2145  	return fmt.Sprintf("https://www.gravatar.com/avatar/%x?s=%d", h.Sum(nil), size)
  2146  }
  2147  
  2148  // AtWho 查找被@的用户名.minLen为用户名最小长度,默认5.
  2149  func (ks *LkkString) AtWho(text string, minLen ...int) []string {
  2150  	var result = []string{}
  2151  	var username string
  2152  	var min int = 5
  2153  	if len(minLen) > 0 && minLen[0] > 0 {
  2154  		min = minLen[0]
  2155  	}
  2156  
  2157  	for _, line := range strings.Split(text, "\n") {
  2158  		if len(line) == 0 {
  2159  			continue
  2160  		}
  2161  		for {
  2162  			index := strings.Index(line, "@")
  2163  			if index == -1 {
  2164  				break
  2165  			} else if index > 0 {
  2166  				r := rune(line[index-1])
  2167  				if unicode.IsUpper(r) || unicode.IsLower(r) {
  2168  					line = line[index+1:]
  2169  				} else {
  2170  					line = line[index:]
  2171  				}
  2172  			} else if index == 0 {
  2173  				// the "@" is first characters
  2174  				endIndex := strings.Index(line, " ")
  2175  				if endIndex == -1 {
  2176  					username = line[1:]
  2177  				} else {
  2178  					username = line[1:endIndex]
  2179  				}
  2180  
  2181  				if len(username) >= min && RegUsernameen.MatchString(username) && !KArr.InStringSlice(username, result) {
  2182  					result = append(result, username)
  2183  				}
  2184  
  2185  				if endIndex == -1 {
  2186  					break
  2187  				}
  2188  
  2189  				line = line[endIndex:]
  2190  			}
  2191  		}
  2192  	}
  2193  
  2194  	return result
  2195  }
  2196  
  2197  // MatchEquations 匹配字符串中所有的等式.
  2198  func (ks *LkkString) MatchEquations(str string) (res []string) {
  2199  	res = RegEquation.FindAllString(equationStr03, -1)
  2200  	return
  2201  }
  2202  
  2203  // GetEquationValue 获取等式str中变量name的值.
  2204  func (ks *LkkString) GetEquationValue(str, name string) (res string) {
  2205  	pattern := `['"]?` + name + `['"]?[\s]*=[\s]*['"]?(.*)['"]?`
  2206  	reg := regexp.MustCompile(pattern)
  2207  	mat := reg.FindStringSubmatch(str)
  2208  	if len(mat) == 2 {
  2209  		res = mat[1]
  2210  	}
  2211  
  2212  	return
  2213  }