初始化项目
This commit is contained in:
55
trunk/goutil/stringUtil/base64.go
Normal file
55
trunk/goutil/stringUtil/base64.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
const (
|
||||
base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
|
||||
// const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
// const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
)
|
||||
|
||||
var coder = base64.NewEncoding(base64Table)
|
||||
|
||||
// 对字符串进行Base64编码
|
||||
func Base64Encode(src string) string {
|
||||
if src == "" {
|
||||
return src
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString([]byte(src))
|
||||
}
|
||||
|
||||
// 对字符串进行Base64解码
|
||||
func Base64Encode2(src []byte) []byte {
|
||||
if len(src) == 0 {
|
||||
return src
|
||||
}
|
||||
|
||||
return []byte(base64.StdEncoding.EncodeToString(src))
|
||||
}
|
||||
|
||||
// 对字符数组进行Base64编码
|
||||
func Base64Decode(src string) (string, error) {
|
||||
if src == "" {
|
||||
return src, nil
|
||||
}
|
||||
|
||||
bytes, err := coder.DecodeString(src)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
// 对字符数组进行Base64解码
|
||||
func Base64Decode2(src []byte) ([]byte, error) {
|
||||
if len(src) == 0 {
|
||||
return src, nil
|
||||
}
|
||||
|
||||
return coder.DecodeString(string(src))
|
||||
}
|
||||
53
trunk/goutil/stringUtil/base64_test.go
Normal file
53
trunk/goutil/stringUtil/base64_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBase64Encode(t *testing.T) {
|
||||
greeting := "Hello world"
|
||||
encoded := Base64Encode(greeting)
|
||||
decoded, err := Base64Decode(encoded)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is one:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if greeting != decoded {
|
||||
t.Errorf("Expected %s, but got %s", greeting, decoded)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64Encode2(t *testing.T) {
|
||||
greeting := []byte("Hello world")
|
||||
encoded := Base64Encode2(greeting)
|
||||
decoded, err := Base64Decode2(encoded)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is one:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if isEqual(greeting, decoded) == false {
|
||||
t.Errorf("Expected %s, but got %s", greeting, decoded)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func isEqual(s1, s2 []byte) bool {
|
||||
if s1 == nil || s2 == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(s1); i++ {
|
||||
if s1[i] != s2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
4
trunk/goutil/stringUtil/doc.go
Normal file
4
trunk/goutil/stringUtil/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
字符串助手类包
|
||||
*/
|
||||
package stringUtil
|
||||
198
trunk/goutil/stringUtil/emojiCharFilter.go
Normal file
198
trunk/goutil/stringUtil/emojiCharFilter.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package stringUtil
|
||||
|
||||
// 表情符号集合
|
||||
var emojiData map[rune]rune
|
||||
|
||||
func init() {
|
||||
emojiData = make(map[rune]rune, 1024)
|
||||
|
||||
addEmojiChar()
|
||||
}
|
||||
|
||||
// 添加一个范围的unicode
|
||||
// start:unicode起始位置
|
||||
// endlist:unicode结束位置
|
||||
func addUnicodeRange(start rune, endlist ...rune) {
|
||||
if len(endlist) <= 0 {
|
||||
// 添加单个的
|
||||
emojiData[start] = start
|
||||
return
|
||||
}
|
||||
|
||||
end := endlist[0]
|
||||
if start > end {
|
||||
return
|
||||
}
|
||||
|
||||
// 添加范围的
|
||||
for i := start; i <= end; i++ {
|
||||
emojiData[i] = i
|
||||
}
|
||||
}
|
||||
|
||||
// 增加emoji表情符号
|
||||
// 表情字符大全参考:
|
||||
// https://zh.wikipedia.org/wiki/%E7%B9%AA%E6%96%87%E5%AD%97
|
||||
// 对应unicode版本号:Unicode 10.0版本
|
||||
func addEmojiChar() {
|
||||
addUnicodeRange(0x00A9)
|
||||
addUnicodeRange(0x00AE)
|
||||
|
||||
addUnicodeRange(0x203C)
|
||||
addUnicodeRange(0x2049)
|
||||
addUnicodeRange(0x2122)
|
||||
addUnicodeRange(0x2139)
|
||||
addUnicodeRange(0x2194, 0x2199)
|
||||
addUnicodeRange(0x21A9, 0x21AA)
|
||||
addUnicodeRange(0x231A, 0x231B)
|
||||
addUnicodeRange(0x2328)
|
||||
addUnicodeRange(0x23CF)
|
||||
addUnicodeRange(0x23E9, 0x23F3)
|
||||
addUnicodeRange(0x23F8, 0x23FA)
|
||||
addUnicodeRange(0x24C2)
|
||||
addUnicodeRange(0x25AA, 0x25AB)
|
||||
addUnicodeRange(0x25B6)
|
||||
addUnicodeRange(0x25C0)
|
||||
addUnicodeRange(0x25FB, 0x25FE)
|
||||
|
||||
addUnicodeRange(0x2600, 0x2604)
|
||||
addUnicodeRange(0x260E)
|
||||
addUnicodeRange(0x2611)
|
||||
addUnicodeRange(0x2614, 0x2615)
|
||||
addUnicodeRange(0x2618)
|
||||
addUnicodeRange(0x261D)
|
||||
addUnicodeRange(0x2620)
|
||||
addUnicodeRange(0x2622, 0x2623)
|
||||
addUnicodeRange(0x2626)
|
||||
addUnicodeRange(0x262A)
|
||||
addUnicodeRange(0x262E, 0x262F)
|
||||
addUnicodeRange(0x2638, 0x263A)
|
||||
addUnicodeRange(0x2640)
|
||||
addUnicodeRange(0x2642)
|
||||
addUnicodeRange(0x2648, 0x2653)
|
||||
addUnicodeRange(0x2660)
|
||||
addUnicodeRange(0x2663)
|
||||
addUnicodeRange(0x2665, 0x2666)
|
||||
addUnicodeRange(0x2668)
|
||||
addUnicodeRange(0x267B)
|
||||
addUnicodeRange(0x267F)
|
||||
addUnicodeRange(0x2692, 0x2697)
|
||||
addUnicodeRange(0x2699)
|
||||
addUnicodeRange(0x269B, 0x269C)
|
||||
|
||||
addUnicodeRange(0x26A0, 0x26A1)
|
||||
addUnicodeRange(0x26AA, 0x26AB)
|
||||
addUnicodeRange(0x26B0, 0x26B1)
|
||||
addUnicodeRange(0x26BD, 0x26BE)
|
||||
addUnicodeRange(0x26C4, 0x26C5)
|
||||
addUnicodeRange(0x26C8)
|
||||
addUnicodeRange(0x26CE, 0x26CF)
|
||||
addUnicodeRange(0x26D1)
|
||||
addUnicodeRange(0x26D3, 0x26D4)
|
||||
addUnicodeRange(0x26E9, 0x26EA)
|
||||
addUnicodeRange(0x26F0, 0x26F5)
|
||||
addUnicodeRange(0x26F7, 0x26FA)
|
||||
addUnicodeRange(0x26FD)
|
||||
|
||||
addUnicodeRange(0x2702)
|
||||
addUnicodeRange(0x2705)
|
||||
addUnicodeRange(0x2708, 0x270D)
|
||||
addUnicodeRange(0x270F)
|
||||
addUnicodeRange(0x2712)
|
||||
addUnicodeRange(0x2714)
|
||||
addUnicodeRange(0x2716)
|
||||
addUnicodeRange(0x271D)
|
||||
addUnicodeRange(0x2721)
|
||||
addUnicodeRange(0x2728)
|
||||
addUnicodeRange(0x2733, 0x2734)
|
||||
addUnicodeRange(0x2744)
|
||||
addUnicodeRange(0x2747)
|
||||
addUnicodeRange(0x274C)
|
||||
addUnicodeRange(0x274E)
|
||||
addUnicodeRange(0x2753, 0x2755)
|
||||
addUnicodeRange(0x2757)
|
||||
addUnicodeRange(0x2763, 0x2764)
|
||||
addUnicodeRange(0x2795, 0x2797)
|
||||
addUnicodeRange(0x27A1)
|
||||
addUnicodeRange(0x27B0)
|
||||
addUnicodeRange(0x27BF)
|
||||
addUnicodeRange(0x2934, 0x2935)
|
||||
addUnicodeRange(0x2B05, 0x2B07)
|
||||
addUnicodeRange(0x2B1B, 0x2B1C)
|
||||
addUnicodeRange(0x2B50)
|
||||
addUnicodeRange(0x2B55)
|
||||
addUnicodeRange(0x3030)
|
||||
addUnicodeRange(0x303D)
|
||||
addUnicodeRange(0x3297, 0x3299)
|
||||
addUnicodeRange(0x3299)
|
||||
addUnicodeRange(0x1F004)
|
||||
addUnicodeRange(0x1F0CF)
|
||||
addUnicodeRange(0x1F170, 0x1F171)
|
||||
addUnicodeRange(0x1F17E, 0x1F17F)
|
||||
addUnicodeRange(0x1F18E)
|
||||
|
||||
addUnicodeRange(0x1F191, 0x1F19A)
|
||||
addUnicodeRange(0x1F201, 0x1F202)
|
||||
addUnicodeRange(0x1F21A)
|
||||
addUnicodeRange(0x1F22F)
|
||||
addUnicodeRange(0x1F232, 0x1F23A)
|
||||
addUnicodeRange(0x1F250, 0x1F251)
|
||||
addUnicodeRange(0x1F300, 0x1F321)
|
||||
addUnicodeRange(0x1F324, 0x1F393)
|
||||
addUnicodeRange(0x1F396, 0x1F397)
|
||||
addUnicodeRange(0x1F399, 0x1F39B)
|
||||
addUnicodeRange(0x1F39E, 0x1F3F0)
|
||||
addUnicodeRange(0x1F3F3, 0x1F3F5)
|
||||
addUnicodeRange(0x1F3F7, 0x1F53D)
|
||||
|
||||
addUnicodeRange(0x1F549, 0x1F54E)
|
||||
addUnicodeRange(0x1F550, 0x1F567)
|
||||
addUnicodeRange(0x1F56F, 0x1F570)
|
||||
addUnicodeRange(0x1F573, 0x1F57A)
|
||||
addUnicodeRange(0x1F587)
|
||||
addUnicodeRange(0x1F58A, 0x1F58D)
|
||||
addUnicodeRange(0x1F590)
|
||||
addUnicodeRange(0x1F595, 0x1F596)
|
||||
addUnicodeRange(0x1F5A4, 0x1F5A5)
|
||||
addUnicodeRange(0x1F5A8)
|
||||
addUnicodeRange(0x1F5B1, 0x1F5B2)
|
||||
addUnicodeRange(0x1F5BC)
|
||||
addUnicodeRange(0x1F5C2, 0x1F5C4)
|
||||
addUnicodeRange(0x1F5D1, 0x1F5D3)
|
||||
addUnicodeRange(0x1F5DC, 0x1F5DE)
|
||||
addUnicodeRange(0x1F5E1)
|
||||
addUnicodeRange(0x1F5E3)
|
||||
addUnicodeRange(0x1F5E8)
|
||||
addUnicodeRange(0x1F5EF)
|
||||
addUnicodeRange(0x1F5F3)
|
||||
addUnicodeRange(0x1F5FA, 0x1F6C5)
|
||||
addUnicodeRange(0x1F6CB, 0x1F6D2)
|
||||
addUnicodeRange(0x1F6E0, 0x1F6E5)
|
||||
addUnicodeRange(0x1F6E8)
|
||||
addUnicodeRange(0x1F6EB, 0x1F6EC)
|
||||
addUnicodeRange(0x1F6F0)
|
||||
addUnicodeRange(0x1F6F3, 0x1F6F8)
|
||||
addUnicodeRange(0x1F910, 0x1F93A)
|
||||
addUnicodeRange(0x1F93B, 0x1F93E)
|
||||
addUnicodeRange(0x1F940, 0x1F945)
|
||||
addUnicodeRange(0x1F947, 0x1F94C)
|
||||
addUnicodeRange(0x1F950, 0x1F96B)
|
||||
addUnicodeRange(0x1F980, 0x1F997)
|
||||
addUnicodeRange(0x1F9C0)
|
||||
addUnicodeRange(0x1F9D0, 0x1F9E6)
|
||||
}
|
||||
|
||||
// 检查是否含有表情字符
|
||||
// val:待查看的字符串
|
||||
// 返回值:
|
||||
// 是否包含有表情字符
|
||||
func IfHaveEmoji(val string) bool {
|
||||
// 由于golang在内存中本来就是使用的Unicode,所以可以直接进行匹配操作
|
||||
for _, charItem := range val {
|
||||
if _, eixst := emojiData[charItem]; eixst {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
34
trunk/goutil/stringUtil/emojiCharFilter_test.go
Normal file
34
trunk/goutil/stringUtil/emojiCharFilter_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test 特殊字符
|
||||
func TestEmoji1(t *testing.T) {
|
||||
tstVal := map[string]string{
|
||||
"中文": "你好啊",
|
||||
"繁体中文": "這是什麼天氣",
|
||||
"泰文": "สวัสดีครับ !",
|
||||
"英文": "helloworld",
|
||||
"越南语": "Đó là gì thời tiết.",
|
||||
"日语": "これは何の天気ですか",
|
||||
"标点符号": "!@#$%^^&*())(__+{}[]|:<>",
|
||||
}
|
||||
|
||||
for key, val := range tstVal {
|
||||
if IfHaveEmoji(val) {
|
||||
t.Errorf("语言处理错误:%s", key)
|
||||
}
|
||||
}
|
||||
|
||||
emojiVal := "☀"
|
||||
if IfHaveEmoji(emojiVal) == false {
|
||||
t.Errorf("表情符号匹配错误:")
|
||||
}
|
||||
|
||||
specialChar := "\\'\""
|
||||
if IfHaveEmoji(specialChar) {
|
||||
t.Errorf("特殊字符匹配错误:")
|
||||
}
|
||||
}
|
||||
60
trunk/goutil/stringUtil/guid.go
Normal file
60
trunk/goutil/stringUtil/guid.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"goutil/securityUtil"
|
||||
)
|
||||
|
||||
// 获取新的GUID字符串
|
||||
// 返回值:
|
||||
// 新的GUID字符串
|
||||
func GetNewGUID() string {
|
||||
b := make([]byte, 48)
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return securityUtil.Md5String(base64.URLEncoding.EncodeToString(b), true)
|
||||
}
|
||||
|
||||
// 生成空的GUID字符串
|
||||
// 返回值:
|
||||
// 空的GUID字符串
|
||||
func GetEmptyGUID() string {
|
||||
return "00000000-0000-0000-0000-000000000000"
|
||||
}
|
||||
|
||||
// 判断GUID是否为空
|
||||
// guid:GUID
|
||||
// 返回值:
|
||||
// 是否为空
|
||||
func IsGUIDEmpty(guid string) bool {
|
||||
if guid == "" || guid == "00000000-0000-0000-0000-000000000000" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 获取新的GUID字符串
|
||||
// 返回值:
|
||||
// 新的GUID字符串
|
||||
func GetNewUUID() string {
|
||||
str := GetNewGUID()
|
||||
var builder strings.Builder
|
||||
builder.WriteString(Substring(str, 0, 8))
|
||||
builder.WriteString("-")
|
||||
builder.WriteString(Substring(str, 8, 4))
|
||||
builder.WriteString("-")
|
||||
builder.WriteString(Substring(str, 12, 4))
|
||||
builder.WriteString("-")
|
||||
builder.WriteString(Substring(str, 16, 4))
|
||||
builder.WriteString("-")
|
||||
builder.WriteString(Substring(str, 20, 12))
|
||||
|
||||
return strings.ToLower(builder.String())
|
||||
}
|
||||
60
trunk/goutil/stringUtil/guid_test.go
Normal file
60
trunk/goutil/stringUtil/guid_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetNewGUID(t *testing.T) {
|
||||
guidMap := make(map[string]bool, 1024)
|
||||
count := 10
|
||||
for i := 0; i < count; i++ {
|
||||
guid := GetNewGUID()
|
||||
guidMap[guid] = true
|
||||
}
|
||||
|
||||
if len(guidMap) != count {
|
||||
t.Errorf("there should be %d 条不重复的数据,但是现在只有%d条", count, len(guidMap))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEmptyGUID(t *testing.T) {
|
||||
guid := GetEmptyGUID()
|
||||
expected := "00000000-0000-0000-0000-000000000000"
|
||||
if guid != expected {
|
||||
t.Errorf("guid should be %s, but now is %s", expected, guid)
|
||||
}
|
||||
}
|
||||
|
||||
// test IsGUIDEmpty
|
||||
func TestIsGUIDEmpty(t *testing.T) {
|
||||
isOk := IsGUIDEmpty("")
|
||||
if isOk == false {
|
||||
t.Error("test is Not pass:")
|
||||
return
|
||||
}
|
||||
|
||||
isOk = IsGUIDEmpty("00000000-0000-0000-0000-000000000000")
|
||||
if isOk == false {
|
||||
t.Error("test is Not pass:00000000-0000-0000-0000-000000000000")
|
||||
return
|
||||
}
|
||||
|
||||
isOk = IsGUIDEmpty("00000000-0000-0000-0000-000000000001")
|
||||
if isOk == true {
|
||||
t.Error("test is Not pass:00000000-0000-0000-0000-000000000001")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNewUUID(t *testing.T) {
|
||||
guidMap := make(map[string]bool, 1024)
|
||||
count := 10
|
||||
for i := 0; i < count; i++ {
|
||||
guid := GetNewUUID()
|
||||
guidMap[guid] = true
|
||||
}
|
||||
|
||||
if len(guidMap) != count {
|
||||
t.Errorf("there should be %d 条不重复的数据,但是现在只有%d条", count, len(guidMap))
|
||||
}
|
||||
}
|
||||
16
trunk/goutil/stringUtil/hash.go
Normal file
16
trunk/goutil/stringUtil/hash.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
// HashCode 获取字符串对应的hashCode值
|
||||
func HashCode(s string) int {
|
||||
v := int(crc32.ChecksumIEEE([]byte(s)))
|
||||
|
||||
if v < 0 {
|
||||
return -v
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
23
trunk/goutil/stringUtil/hash_test.go
Normal file
23
trunk/goutil/stringUtil/hash_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test1(t *testing.T) {
|
||||
s := HashCode("abc")
|
||||
s1 := HashCode("abc")
|
||||
|
||||
if s != s1 {
|
||||
t.Errorf("s1 hashcode:%v,s2 hashcode:%v,2个code值不相等", s, s1)
|
||||
}
|
||||
}
|
||||
|
||||
func Test2(t *testing.T) {
|
||||
s := HashCode("abc")
|
||||
s1 := HashCode("bcd")
|
||||
|
||||
if s == s1 {
|
||||
t.Errorf("s1 hashcode:%v,s2 hashcode:%v,2个code值相等", s, s1)
|
||||
}
|
||||
}
|
||||
86
trunk/goutil/stringUtil/similarity.go
Normal file
86
trunk/goutil/stringUtil/similarity.go
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
使用编辑距离Edit Distance的方式来计算两个字符串的相似类。
|
||||
参考资料:https://en.wikipedia.org/wiki/Edit_distance
|
||||
*/
|
||||
package stringUtil
|
||||
|
||||
// 计算两个字符串的相似度
|
||||
// word1: 第一个字符串
|
||||
// word2: 第二个字符串
|
||||
// 返回值:
|
||||
// 两个字符串的距离,表示两个字符串经过多少次变换,可以变成同一个字符串
|
||||
// 两个字符串的相似度,范围为[0, 1]
|
||||
func Similarity(word1, word2 string) (distance int, similarity float64) {
|
||||
// 内部方法,用于计算最小值、最大值
|
||||
min := func(nums ...int) int {
|
||||
_min := nums[0]
|
||||
for _, v := range nums {
|
||||
if v < _min {
|
||||
_min = v
|
||||
}
|
||||
}
|
||||
return _min
|
||||
}
|
||||
max := func(nums ...int) int {
|
||||
_max := nums[0]
|
||||
for _, v := range nums {
|
||||
if v > _max {
|
||||
_max = v
|
||||
}
|
||||
}
|
||||
return _max
|
||||
}
|
||||
|
||||
// 如果有单词为空,或者单词相同,则直接计算出结果,无需进一步计算
|
||||
m, n := len(word1), len(word2)
|
||||
if m == 0 {
|
||||
distance = n
|
||||
return
|
||||
}
|
||||
if n == 0 {
|
||||
distance = m
|
||||
return
|
||||
}
|
||||
if m == n && word1 == word2 {
|
||||
distance = 0
|
||||
similarity = 1
|
||||
return
|
||||
}
|
||||
|
||||
// 使用动态规划计算编辑距离(Edit Distance)
|
||||
// Step 1: define the data structure
|
||||
dp := make([][]int, m+1, m+1)
|
||||
for i := 0; i <= m; i++ {
|
||||
dp[i] = make([]int, n+1, n+1)
|
||||
}
|
||||
|
||||
// Step 2: init the data
|
||||
for i := 0; i <= m; i++ {
|
||||
for j := 0; j <= n; j++ {
|
||||
if i == 0 {
|
||||
dp[i][j] = j
|
||||
}
|
||||
if j == 0 {
|
||||
dp[i][j] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: state transition equation
|
||||
for i := 1; i <= m; i++ {
|
||||
for j := 1; j <= n; j++ {
|
||||
if word1[i-1] == word2[j-1] {
|
||||
dp[i][j] = dp[i-1][j-1]
|
||||
} else {
|
||||
dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 得到距离并计算相似度
|
||||
distance = dp[m][n]
|
||||
maxLength := max(m, n)
|
||||
similarity = float64(maxLength-distance) / float64(maxLength)
|
||||
|
||||
return
|
||||
}
|
||||
91
trunk/goutil/stringUtil/similarity_test.go
Normal file
91
trunk/goutil/stringUtil/similarity_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimilarity(t *testing.T) {
|
||||
source := ""
|
||||
target := ""
|
||||
expectedDistance := 0
|
||||
expectedSimilarity := 0.0
|
||||
gotDistance, gotSimilarity := Similarity(source, target)
|
||||
if gotDistance != expectedDistance {
|
||||
t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance)
|
||||
return
|
||||
}
|
||||
if gotSimilarity != expectedSimilarity {
|
||||
t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity)
|
||||
return
|
||||
}
|
||||
|
||||
source = "Hello"
|
||||
target = ""
|
||||
expectedDistance = 5
|
||||
expectedSimilarity = 0.0
|
||||
gotDistance, gotSimilarity = Similarity(source, target)
|
||||
if gotDistance != expectedDistance {
|
||||
t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance)
|
||||
return
|
||||
}
|
||||
if gotSimilarity != expectedSimilarity {
|
||||
t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity)
|
||||
return
|
||||
}
|
||||
|
||||
source = ""
|
||||
target = "Hello"
|
||||
expectedDistance = 5
|
||||
expectedSimilarity = 0.0
|
||||
gotDistance, gotSimilarity = Similarity(source, target)
|
||||
if gotDistance != expectedDistance {
|
||||
t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance)
|
||||
return
|
||||
}
|
||||
if gotSimilarity != expectedSimilarity {
|
||||
t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity)
|
||||
return
|
||||
}
|
||||
|
||||
source = "Helo"
|
||||
target = "Hello"
|
||||
expectedDistance = 1
|
||||
expectedSimilarity = 4.0 / 5.0
|
||||
gotDistance, gotSimilarity = Similarity(source, target)
|
||||
if gotDistance != expectedDistance {
|
||||
t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance)
|
||||
return
|
||||
}
|
||||
if gotSimilarity != expectedSimilarity {
|
||||
t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity)
|
||||
return
|
||||
}
|
||||
|
||||
source = "kitten"
|
||||
target = "sitten"
|
||||
expectedDistance = 1
|
||||
expectedSimilarity = 5.0 / 6.0
|
||||
gotDistance, gotSimilarity = Similarity(source, target)
|
||||
if gotDistance != expectedDistance {
|
||||
t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance)
|
||||
return
|
||||
}
|
||||
if gotSimilarity != expectedSimilarity {
|
||||
t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity)
|
||||
return
|
||||
}
|
||||
|
||||
source = "Michael Jordan"
|
||||
target = "Michael Jordan"
|
||||
expectedDistance = 0
|
||||
expectedSimilarity = 1
|
||||
gotDistance, gotSimilarity = Similarity(source, target)
|
||||
if gotDistance != expectedDistance {
|
||||
t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance)
|
||||
return
|
||||
}
|
||||
if gotSimilarity != expectedSimilarity {
|
||||
t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity)
|
||||
return
|
||||
}
|
||||
}
|
||||
330
trunk/goutil/stringUtil/split.go
Normal file
330
trunk/goutil/stringUtil/split.go
Normal file
@@ -0,0 +1,330 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"goutil/mathUtil"
|
||||
)
|
||||
|
||||
// 使用多分隔符来进行分割(默认分隔符为:",", ";", ":", "|", "||")
|
||||
// eg:1,2;3|4||5,6;7|8||9
|
||||
// 返回值:
|
||||
// []string
|
||||
func Split(s string, seps []string) []string {
|
||||
retList := make([]string, 0, 32)
|
||||
|
||||
// 如果seps为nil,则使用默认值
|
||||
if seps == nil {
|
||||
seps = []string{",", ";", ":", "|", "||"}
|
||||
}
|
||||
|
||||
// 根据所有的分隔符来一点一点地切割字符串,直到不可切割为止
|
||||
for {
|
||||
startIndex := len(s) - 1
|
||||
endIndex := 0
|
||||
exists := false
|
||||
|
||||
// 遍历,找到第一个分割的位置
|
||||
for _, sep := range seps {
|
||||
index := strings.Index(s, sep)
|
||||
|
||||
// 如果找到有匹配项,则寻找最小的pos,如果有多个相同的pos,则使用长度最长的分隔符
|
||||
if index > -1 {
|
||||
exists = true
|
||||
|
||||
// 说明有多个有效的分隔符,如|和||
|
||||
if index < startIndex {
|
||||
startIndex = index
|
||||
endIndex = startIndex + len(sep) - 1
|
||||
} else if index == startIndex {
|
||||
if startIndex+len(sep)-1 > endIndex {
|
||||
endIndex = startIndex + len(sep) - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到匹配的pos,则分割过程结束
|
||||
if !exists {
|
||||
retList = append(retList, s)
|
||||
break
|
||||
}
|
||||
|
||||
// 切割字符串
|
||||
sub := s[:startIndex]
|
||||
if sub != "" {
|
||||
retList = append(retList, sub)
|
||||
}
|
||||
s = s[endIndex+1:]
|
||||
}
|
||||
|
||||
return retList
|
||||
}
|
||||
|
||||
// 将字符串切割为[]int
|
||||
// str:输入字符串
|
||||
// 返回值:
|
||||
// []int
|
||||
// error
|
||||
func SplitToIntSlice(s, sep string) ([]int, error) {
|
||||
// 先按照分隔符进行切割
|
||||
strSlice := strings.Split(s, sep)
|
||||
|
||||
// 定义int slice
|
||||
intSlice := make([]int, 0, len(strSlice))
|
||||
for _, value := range strSlice {
|
||||
// 去除空格
|
||||
if value = strings.TrimSpace(value); value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if value_int, err := strconv.Atoi(value); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
intSlice = append(intSlice, value_int)
|
||||
}
|
||||
}
|
||||
|
||||
return intSlice, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为[]int32
|
||||
// s:输入字符串
|
||||
// 返回值:
|
||||
// []int
|
||||
// error
|
||||
func SplitToInt32Slice(s, sep string) ([]int32, error) {
|
||||
// 先获得int slice
|
||||
count := 0
|
||||
intSlice, err := SplitToIntSlice(s, sep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
count = len(intSlice)
|
||||
}
|
||||
|
||||
// 定义int32 slice
|
||||
int32Slice := make([]int32, 0, count)
|
||||
for _, item := range intSlice {
|
||||
int32Slice = append(int32Slice, int32(item))
|
||||
}
|
||||
|
||||
return int32Slice, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为[]int64
|
||||
// s:输入字符串
|
||||
// 返回值:
|
||||
// []int64
|
||||
// error
|
||||
func SplitToInt64Slice(s, sep string) ([]int64, error) {
|
||||
// 先获得int slice
|
||||
count := 0
|
||||
intSlice, err := SplitToIntSlice(s, sep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
count = len(intSlice)
|
||||
}
|
||||
|
||||
// 定义int32 slice
|
||||
int64Slice := make([]int64, 0, count)
|
||||
for _, item := range intSlice {
|
||||
int64Slice = append(int64Slice, int64(item))
|
||||
}
|
||||
|
||||
return int64Slice, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为[]float64
|
||||
// s:输入字符串
|
||||
// 返回值:
|
||||
// []float64
|
||||
// error
|
||||
func SplitToFloat64Slice(s, sep string) ([]float64, error) {
|
||||
// 先按照分隔符进行切割
|
||||
strSlice := strings.Split(s, sep)
|
||||
|
||||
// 定义float64 slice
|
||||
floatSlice := make([]float64, 0, len(strSlice))
|
||||
for _, value := range strSlice {
|
||||
// 去除空格
|
||||
if value = strings.TrimSpace(value); value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if value_float, err := strconv.ParseFloat(value, 64); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
floatSlice = append(floatSlice, value_float)
|
||||
}
|
||||
}
|
||||
|
||||
return floatSlice, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为map[int32]int32
|
||||
// s:输入字符串
|
||||
// 返回值:
|
||||
// map[int32]float32
|
||||
// error
|
||||
func SplitToDict_KintVint(s, outerSep, innerSep string) (map[int32]int32, error) {
|
||||
// 先按照分隔符进行切割
|
||||
outerSlice := strings.Split(s, outerSep)
|
||||
|
||||
// 定义map[int32]float32
|
||||
floatMap := make(map[int32]int32, len(outerSlice))
|
||||
for _, itemStr := range outerSlice {
|
||||
innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep)
|
||||
key := strings.TrimSpace(innerSlice[0])
|
||||
value := strings.TrimSpace(innerSlice[1])
|
||||
|
||||
key_int, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value_int, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
floatMap[int32(key_int)] = int32(value_int)
|
||||
}
|
||||
return floatMap, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为map[int32]string
|
||||
// s:输入字符串
|
||||
// 返回值:
|
||||
// map[int32]string
|
||||
// error
|
||||
func SplitToDict_KintVstring(s, outerSep, innerSep string) (map[int32]string, error) {
|
||||
// 先按照分隔符进行切割
|
||||
outerSlice := strings.Split(s, outerSep)
|
||||
|
||||
// 定义map[int32]string
|
||||
resultMap := make(map[int32]string, len(outerSlice))
|
||||
for _, itemStr := range outerSlice {
|
||||
innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep)
|
||||
key := strings.TrimSpace(innerSlice[0])
|
||||
value := strings.TrimSpace(innerSlice[1])
|
||||
|
||||
key_int, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultMap[int32(key_int)] = value
|
||||
}
|
||||
return resultMap, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为map[int32]float32
|
||||
// s:输入字符串
|
||||
// 返回值:
|
||||
// map[int32]float32
|
||||
// error
|
||||
func SplitToDict_KintVfloat(s, outerSep, innerSep string) (map[int32]float32, error) {
|
||||
// 先按照分隔符进行切割
|
||||
outerSlice := strings.Split(s, outerSep)
|
||||
|
||||
// 定义map[int32]float32
|
||||
floatMap := make(map[int32]float32, len(outerSlice))
|
||||
for _, itemStr := range outerSlice {
|
||||
innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep)
|
||||
key := strings.TrimSpace(innerSlice[0])
|
||||
value := strings.TrimSpace(innerSlice[1])
|
||||
|
||||
key_int, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value_float, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
floatMap[int32(key_int)] = float32(value_float)
|
||||
}
|
||||
return floatMap, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为map[int32]float32
|
||||
// s:输入字符串
|
||||
// 返回值:
|
||||
// map[int32]float32
|
||||
// error
|
||||
func SplitToDict_KintVfloat64(s, outerSep, innerSep string) (map[int32]float64, error) {
|
||||
// 先按照分隔符进行切割
|
||||
outerSlice := strings.Split(s, outerSep)
|
||||
|
||||
// 定义map[int32]float32
|
||||
floatMap := make(map[int32]float64, len(outerSlice))
|
||||
for _, itemStr := range outerSlice {
|
||||
innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep)
|
||||
key := strings.TrimSpace(innerSlice[0])
|
||||
value := strings.TrimSpace(innerSlice[1])
|
||||
|
||||
key_int, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value_float, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
floatMap[int32(key_int)] = float64(value_float)
|
||||
}
|
||||
return floatMap, nil
|
||||
}
|
||||
|
||||
// 将字符串切割为IntRegion列表
|
||||
// s:输入字符串,形如:1-200,201-400,401-1000
|
||||
// outerSep:外部分隔符
|
||||
// innerSep:内部分隔符
|
||||
// 返回值:
|
||||
// IntRegion列表
|
||||
// 错误对象
|
||||
func SplitToIntRegion(s, outerSep, innerSep string) (intRegionList []*mathUtil.IntRegion, err error) {
|
||||
if s == "" {
|
||||
err = fmt.Errorf("Input is empty")
|
||||
return
|
||||
}
|
||||
|
||||
outerRegionList := make([]string, 0, 4)
|
||||
outerRegionList = strings.Split(s, outerSep)
|
||||
if len(outerRegionList) == 0 {
|
||||
err = fmt.Errorf("%s:Format invalid. Such as:1-100,101-200", s)
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range outerRegionList {
|
||||
innerRegionList := make([]string, 0, 2)
|
||||
innerRegionList = strings.Split(item, innerSep)
|
||||
if len(innerRegionList) != 2 {
|
||||
err = fmt.Errorf("%s:Format invalid. Such as:1-100", item)
|
||||
return
|
||||
}
|
||||
|
||||
var lower, upper int
|
||||
lower, err = strconv.Atoi(innerRegionList[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
upper, err = strconv.Atoi(innerRegionList[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if lower > upper {
|
||||
err = fmt.Errorf("lower:%d should less than upper:%d", lower, upper)
|
||||
return
|
||||
}
|
||||
|
||||
intRegionList = append(intRegionList, mathUtil.NewIntRegion(lower, upper))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
78
trunk/goutil/stringUtil/split_test.go
Normal file
78
trunk/goutil/stringUtil/split_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSplit(t *testing.T) {
|
||||
s := "1,2;3|4||5,6;7|8||9,"
|
||||
// seps := []string{",", ";", "|", "||"}
|
||||
retList := Split(s, nil)
|
||||
if retList[0] != "1" || retList[1] != "2" || retList[2] != "3" || retList[3] != "4" || retList[4] != "5" || retList[5] != "6" || retList[6] != "7" || retList[7] != "8" || retList[8] != "9" {
|
||||
t.Errorf("ecptected:123456789, but now got:%v", retList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitToIntSlice(t *testing.T) {
|
||||
s := "1, 2, 3, 4, 5, a"
|
||||
if _, err := SplitToIntSlice(s, ","); err == nil {
|
||||
t.Errorf("Expected got err, but got nil")
|
||||
}
|
||||
|
||||
s = "1, 5, 39,"
|
||||
if intSlice, err := SplitToIntSlice(s, ","); err != nil {
|
||||
t.Errorf("Expected got nil, but got error:%s", err)
|
||||
} else {
|
||||
// fmt.Printf("intSlice:%v\n", intSlice)
|
||||
if intSlice[0] != 1 || intSlice[1] != 5 || intSlice[2] != 39 {
|
||||
t.Errorf("Expected got %s, but got %v", s, intSlice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitToIntRegion(t *testing.T) {
|
||||
idRegionStr := ""
|
||||
outerSep := ","
|
||||
innerSep := "-"
|
||||
var err error
|
||||
|
||||
if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil {
|
||||
t.Errorf("PraseIdRegion should failed, but now not.err:%s", err)
|
||||
}
|
||||
|
||||
idRegionStr = ","
|
||||
if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil {
|
||||
t.Errorf("PraseIdRegion should failed, but now not.err:%s", err)
|
||||
}
|
||||
|
||||
idRegionStr = "1-100,101,200"
|
||||
if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil {
|
||||
t.Errorf("PraseIdRegion should failed, but now not.err:%s", err)
|
||||
}
|
||||
|
||||
idRegionStr = "1-100,101-20"
|
||||
if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil {
|
||||
t.Errorf("PraseIdRegion should failed, but now not.err:%s", err)
|
||||
}
|
||||
|
||||
idRegionStr = "1-100,101-200"
|
||||
if idRegionList, err := SplitToIntRegion(idRegionStr, outerSep, innerSep); err != nil {
|
||||
t.Errorf("PraseIdRegion should succeed, but now failed.err:%s", err)
|
||||
} else {
|
||||
if idRegionList[0].Lower != 1 || idRegionList[0].Upper != 100 ||
|
||||
idRegionList[1].Lower != 101 || idRegionList[1].Upper != 200 {
|
||||
t.Errorf("SplitToIntRegion should succeed, but now failed. idRegionStr:%s, idRegionList:%v", idRegionStr, idRegionList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitToFloat64(t *testing.T) {
|
||||
result, err := SplitToFloat64Slice("1.11,2.22", ",")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%v\n", result)
|
||||
}
|
||||
142
trunk/goutil/stringUtil/string.go
Normal file
142
trunk/goutil/stringUtil/string.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// 检查一个字符串是否是空字符串
|
||||
// content:上下文字符串
|
||||
// 返回值:
|
||||
// bool:true:空字符串 false:非空字符串
|
||||
func IsEmpty(content string) bool {
|
||||
if len(content) <= 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return strings.IndexFunc(content, func(item rune) bool {
|
||||
return unicode.IsSpace(item) == false
|
||||
}) < 0
|
||||
}
|
||||
|
||||
// 截取字符串
|
||||
// start:开始位置
|
||||
// length:截取长度
|
||||
// 返回值:
|
||||
// 截取后的字符串
|
||||
func Substring(str string, start, length int) string {
|
||||
// 先将字符串转化为[]rune格式(由于rune是字符串的基本单位)
|
||||
runeString := []rune(str)
|
||||
runeLength := len(runeString)
|
||||
end := 0
|
||||
|
||||
// 计算起始位置
|
||||
if start > runeLength {
|
||||
start = runeLength
|
||||
}
|
||||
|
||||
// 计算终止位置
|
||||
end = start + length
|
||||
if end > runeLength {
|
||||
end = runeLength
|
||||
}
|
||||
|
||||
if start > end {
|
||||
start, end = end, start
|
||||
}
|
||||
|
||||
return string(runeString[start:end])
|
||||
}
|
||||
|
||||
// 根据不同平台获取换行符
|
||||
// 返回值:
|
||||
// 换行符
|
||||
func GetNewLineString() string {
|
||||
switch os := runtime.GOOS; os {
|
||||
case "windows":
|
||||
return "\r\n"
|
||||
default:
|
||||
return "\n"
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否存在特殊符号
|
||||
// 1. emoji字符
|
||||
// 2. ascii控制字符
|
||||
// 3. \ " '
|
||||
// val:待检查的字符串
|
||||
// 返回值:
|
||||
// bool:true:有特殊字符 false:无特殊字符
|
||||
func IfHaveSpecialChar(val string) bool {
|
||||
if len(val) <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// 表情符号过滤
|
||||
// Wide UCS-4 build
|
||||
emojiReg, _ := regexp.Compile("[^\U00000000-\U0000FFFF]+")
|
||||
if emojiReg.Match([]byte(val)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 排除控制字符和特殊字符
|
||||
for _, charItem := range val {
|
||||
// 排除控制字符
|
||||
if (charItem > 0 && charItem < 0x20) || charItem == 0x7F {
|
||||
return true
|
||||
}
|
||||
|
||||
// 排除部分特殊字符: \ " '
|
||||
switch charItem {
|
||||
case '\\':
|
||||
fallthrough
|
||||
case '"':
|
||||
fallthrough
|
||||
case '\'':
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断string数组是否内容唯一
|
||||
func IsDistinct_string(list []string) (result bool) {
|
||||
if len(list) == 0 || len(list) == 1 {
|
||||
result = true
|
||||
return
|
||||
}
|
||||
|
||||
sort.Strings(list)
|
||||
|
||||
for i := 0; i < len(list)-1; i++ {
|
||||
if list[i] == list[i+1] {
|
||||
result = false
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
result = true
|
||||
return
|
||||
}
|
||||
|
||||
// 验证是否是电话号码
|
||||
func VerifyPhone(phone string) bool {
|
||||
regular := "^1[3-9]\\d{9}$"
|
||||
|
||||
reg := regexp.MustCompile(regular)
|
||||
return reg.MatchString(phone)
|
||||
}
|
||||
|
||||
// 转型成int64
|
||||
func StringToInt64(str string) int64 {
|
||||
num, err := strconv.ParseInt(str, 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return num
|
||||
}
|
||||
57
trunk/goutil/stringUtil/string_builder.go
Normal file
57
trunk/goutil/stringUtil/string_builder.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type StringBuilder struct {
|
||||
buffer bytes.Buffer
|
||||
}
|
||||
|
||||
func NewStringBuilder() *StringBuilder {
|
||||
var builder StringBuilder
|
||||
return &builder
|
||||
}
|
||||
|
||||
func (builder *StringBuilder) Append(format string, args ...interface{}) *StringBuilder {
|
||||
if len(args) > 0 {
|
||||
format = fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
builder.buffer.WriteString(format)
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder *StringBuilder) AppendLine(format string, args ...interface{}) *StringBuilder {
|
||||
if len(args) > 0 {
|
||||
format = fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
builder.buffer.WriteString(format + "\n")
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder *StringBuilder) AppendStrings(ss ...string) *StringBuilder {
|
||||
for i := range ss {
|
||||
builder.buffer.WriteString(ss[i])
|
||||
}
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder *StringBuilder) AppendLines(ss ...string) *StringBuilder {
|
||||
for i := range ss {
|
||||
builder.buffer.WriteString(ss[i] + "\n")
|
||||
}
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder *StringBuilder) Clear() *StringBuilder {
|
||||
var buffer bytes.Buffer
|
||||
builder.buffer = buffer
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder *StringBuilder) ToString() string {
|
||||
return builder.buffer.String()
|
||||
}
|
||||
120
trunk/goutil/stringUtil/string_test.go
Normal file
120
trunk/goutil/stringUtil/string_test.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test IsEmpty
|
||||
func TestIsEmpty(t *testing.T) {
|
||||
isOk := IsEmpty("")
|
||||
if isOk == false {
|
||||
t.Error("\"\" test is Not pass")
|
||||
return
|
||||
}
|
||||
|
||||
isOk = IsEmpty(" ")
|
||||
if isOk == false {
|
||||
t.Error("\" \" test is Not pass")
|
||||
return
|
||||
}
|
||||
|
||||
isOk = IsEmpty(" \t\n")
|
||||
if isOk == false {
|
||||
t.Error("\" \\t\\n\" test is Not pass")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubstr(t *testing.T) {
|
||||
str := "Hello, Jordan.左贤清"
|
||||
substr := Substring(str, 0, 5)
|
||||
expectedstr := "Hello"
|
||||
|
||||
if substr != expectedstr {
|
||||
t.Errorf("Failed. Expected:%s, Got %s\n", expectedstr, substr)
|
||||
}
|
||||
|
||||
substr = Substring(str, 0, 10)
|
||||
expectedstr = "Hello, Jor"
|
||||
|
||||
if substr != expectedstr {
|
||||
t.Errorf("Failed. Expected:%s, Got %s\n", expectedstr, substr)
|
||||
}
|
||||
|
||||
substr = Substring(str, 0, 15)
|
||||
expectedstr = "Hello, Jordan.左"
|
||||
|
||||
if substr != expectedstr {
|
||||
t.Errorf("Failed. Expected:%s, Got %s\n", expectedstr, substr)
|
||||
}
|
||||
|
||||
substr = Substring(str, 0, 20)
|
||||
expectedstr = "Hello, Jordan.左贤清"
|
||||
|
||||
if substr != expectedstr {
|
||||
t.Errorf("Failed. Expected:%s, Got %s\n", expectedstr, substr)
|
||||
}
|
||||
|
||||
guid1 := GetNewGUID()
|
||||
guid2 := GetNewGUID()
|
||||
fmt.Printf("guid1:%s, guid2:%s\n", guid1, guid2)
|
||||
fmt.Printf("length of %s is %d\n", guid1, len(guid1))
|
||||
if guid1 == guid2 {
|
||||
t.Errorf("%s should not be equal with %s", guid1, guid2)
|
||||
}
|
||||
}
|
||||
|
||||
// test 特殊字符
|
||||
func TestIfHaveSpecialChar(t *testing.T) {
|
||||
tstVal := map[string]string{
|
||||
"中文": "你好啊",
|
||||
"繁体中文": "這是什麼天氣",
|
||||
"泰文": "สวัสดีครับ !",
|
||||
"英文": "helloworld",
|
||||
"越南语": "Đó là gì thời tiết.",
|
||||
"日语": "これは何の天気ですか",
|
||||
"标点符号": "!@#$%^^&*())(__+{}[]|:<>",
|
||||
}
|
||||
|
||||
for key, val := range tstVal {
|
||||
if IfHaveSpecialChar(val) {
|
||||
t.Errorf("语言处理错误:%s", key)
|
||||
}
|
||||
}
|
||||
|
||||
specialChar := "\\'\""
|
||||
if IfHaveSpecialChar(specialChar) == false {
|
||||
t.Errorf("特殊字符匹配错误:")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDistinct_string(t *testing.T) {
|
||||
list := make([]string, 0, 8)
|
||||
result := IsDistinct_string(list)
|
||||
fmt.Printf("list:%v,result:%v-------1\n", list, result)
|
||||
if result == false {
|
||||
t.Errorf("it's should be true, but now false-------1")
|
||||
}
|
||||
|
||||
list = append(list, "Hello")
|
||||
result = IsDistinct_string(list)
|
||||
fmt.Printf("list:%v,result:%v-------2\n", list, result)
|
||||
if result == false {
|
||||
t.Errorf("it's should be true, but now false-------2")
|
||||
}
|
||||
|
||||
list = append(list, "Hello")
|
||||
result = IsDistinct_string(list)
|
||||
fmt.Printf("list:%v,result:%v-------3\n", list, result)
|
||||
if result {
|
||||
t.Errorf("it's should be false, but now true-------3")
|
||||
}
|
||||
|
||||
list = append(list, "")
|
||||
result = IsDistinct_string(list)
|
||||
fmt.Printf("list:%v,result:%v-------4\n", list, result)
|
||||
if result {
|
||||
t.Errorf("it's should be false, but now true-------4")
|
||||
}
|
||||
}
|
||||
158
trunk/goutil/stringUtil/toString.go
Normal file
158
trunk/goutil/stringUtil/toString.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// map转换为字符串(如果类型不匹配)
|
||||
// data:map数据
|
||||
// separator1:间隔符1
|
||||
// separator1:间隔符2
|
||||
// 返回值:
|
||||
// result:转换后的字符串
|
||||
// err:错误信息
|
||||
func MapToString(data interface{}, separator1, separator2 string) (result string, err error) {
|
||||
if data == nil {
|
||||
return
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(data)
|
||||
if val.Kind() != reflect.Map {
|
||||
err = fmt.Errorf("只能转换Map类型的,当前类型是:%v", val.Kind().String())
|
||||
return
|
||||
}
|
||||
|
||||
if val.Len() <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, keyItem := range val.MapKeys() {
|
||||
valItem := val.MapIndex(keyItem)
|
||||
result = result + fmt.Sprintf("%v%s%v%s", keyItem.Interface(), separator1, valItem.Interface(), separator2)
|
||||
}
|
||||
|
||||
result = result[:len(result)-1]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// map转换为字符串(如果类型不匹配)
|
||||
// data:map数据
|
||||
// separator1:间隔符1
|
||||
// separator1:间隔符2
|
||||
// valGetFunc:结果值获取函数
|
||||
// 返回值:
|
||||
// result:转换后的字符串
|
||||
// err:错误信息
|
||||
func MapToString2(data interface{}, separator1, separator2 string, valGetFunc func(val interface{}) interface{}) (result string, err error) {
|
||||
if data == nil {
|
||||
return
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(data)
|
||||
if val.Kind() != reflect.Map {
|
||||
err = fmt.Errorf("只能转换Map类型的,当前类型是:%v", val.Kind().String())
|
||||
return
|
||||
}
|
||||
|
||||
if val.Len() <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, keyItem := range val.MapKeys() {
|
||||
valItem := val.MapIndex(keyItem)
|
||||
result = result + fmt.Sprintf("%v%s%v%s", keyItem.Interface(), separator1, valGetFunc(valItem.Interface()), separator2)
|
||||
}
|
||||
|
||||
result = result[:len(result)-1]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 把一个集合转换成字符串
|
||||
// data:slice类型的集合
|
||||
// separator:分隔符
|
||||
// 返回值:
|
||||
// result:转换后的字符串
|
||||
// err:错误信息对象
|
||||
func SliceToString(data interface{}, separator string) (result string, err error) {
|
||||
if data == nil {
|
||||
return
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(data)
|
||||
if value.Kind() != reflect.Slice && value.Kind() != reflect.Array {
|
||||
err = fmt.Errorf("目标类型不正确,只能是slice或array 当前类型是:%v", value.Kind().String())
|
||||
return
|
||||
}
|
||||
|
||||
if value.Len() <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
valItem := value.Index(i)
|
||||
result = result + fmt.Sprintf("%s%v", separator, valItem.Interface())
|
||||
}
|
||||
result = result[1:]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func StringListToString(list []string, delimiter string) string {
|
||||
var buffer bytes.Buffer
|
||||
for i, v := range list {
|
||||
if i != len(list)-1 {
|
||||
buffer.WriteString(v)
|
||||
buffer.WriteString(delimiter)
|
||||
} else {
|
||||
buffer.WriteString(v)
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func IntListToString(list []int, delimiter string) string {
|
||||
var buffer bytes.Buffer
|
||||
for i, v := range list {
|
||||
if i != len(list)-1 {
|
||||
buffer.WriteString(fmt.Sprintf("%d", v))
|
||||
buffer.WriteString(delimiter)
|
||||
} else {
|
||||
buffer.WriteString(fmt.Sprintf("%d", v))
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func Int32ListToString(list []int32, delimiter string) string {
|
||||
var buffer bytes.Buffer
|
||||
for i, v := range list {
|
||||
if i != len(list)-1 {
|
||||
buffer.WriteString(fmt.Sprintf("%d", v))
|
||||
buffer.WriteString(delimiter)
|
||||
} else {
|
||||
buffer.WriteString(fmt.Sprintf("%d", v))
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func Int64ListToString(list []int64, delimiter string) string {
|
||||
var buffer bytes.Buffer
|
||||
for i, v := range list {
|
||||
if i != len(list)-1 {
|
||||
buffer.WriteString(fmt.Sprintf("%d", v))
|
||||
buffer.WriteString(delimiter)
|
||||
} else {
|
||||
buffer.WriteString(fmt.Sprintf("%d", v))
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
169
trunk/goutil/stringUtil/toString_test.go
Normal file
169
trunk/goutil/stringUtil/toString_test.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMapToString(t *testing.T) {
|
||||
var data map[string]int
|
||||
separator1 := ","
|
||||
separator2 := ";"
|
||||
|
||||
got, err := MapToString(data, separator1, separator2)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
data1 := make([]int, 0, 4)
|
||||
data1 = append(data1, 1)
|
||||
got, err = MapToString(data1, separator1, separator2)
|
||||
if err == nil {
|
||||
t.Errorf("There should be an error, but now there is not")
|
||||
return
|
||||
}
|
||||
|
||||
data2 := make(map[string]int, 4)
|
||||
data2["Jordan"] = 34
|
||||
data2["Thomas"] = 6
|
||||
expected1 := "Jordan,34;Thomas,6"
|
||||
expected2 := "Thomas,6;Jordan,34"
|
||||
|
||||
got, err = MapToString(data2, separator1, separator2)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is:%s", err)
|
||||
return
|
||||
}
|
||||
if got != expected1 && got != expected2 {
|
||||
t.Errorf("Expected to get:%s or %s, but got:%s", expected1, expected2, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapToString2(t *testing.T) {
|
||||
var data map[string]int
|
||||
separator1 := ","
|
||||
separator2 := ";"
|
||||
|
||||
got, err := MapToString2(data, separator1, separator2, valGetFunc)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
data1 := make([]int, 0, 4)
|
||||
data1 = append(data1, 1)
|
||||
got, err = MapToString2(data1, separator1, separator2, valGetFunc)
|
||||
if err == nil {
|
||||
t.Errorf("There should be an error, but now there is not")
|
||||
return
|
||||
}
|
||||
|
||||
data2 := make(map[string]int, 4)
|
||||
data2["Jordan"] = 34
|
||||
data2["Thomas"] = 6
|
||||
expected1 := "Jordan,34;Thomas,6"
|
||||
expected2 := "Thomas,6;Jordan,34"
|
||||
|
||||
got, err = MapToString2(data2, separator1, separator2, valGetFunc)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is:%s", err)
|
||||
return
|
||||
}
|
||||
if got != expected1 && got != expected2 {
|
||||
t.Errorf("Expected to get:%s or %s, but got:%s", expected1, expected2, got)
|
||||
}
|
||||
}
|
||||
|
||||
func valGetFunc(val interface{}) interface{} {
|
||||
return val
|
||||
}
|
||||
|
||||
func TestSliceToString(t *testing.T) {
|
||||
// Test with nil value
|
||||
var value interface{} = nil
|
||||
expected := ""
|
||||
got, err := SliceToString(value, ",")
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now got one. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Test with wrong type value
|
||||
value = "hello"
|
||||
got, err = SliceToString(value, ",")
|
||||
if err == nil {
|
||||
t.Errorf("There should be an error, but now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
// Test with correct value
|
||||
value = []int{1, 2, 3, 4, 5}
|
||||
expected = "1,2,3,4,5"
|
||||
|
||||
got, err = SliceToString(value, ",")
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now got one. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if got != expected {
|
||||
t.Errorf("Expected %s, but got %s", expected, got)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringListToString(t *testing.T) {
|
||||
list := make([]string, 0, 4)
|
||||
list = append(list, "Hello")
|
||||
list = append(list, "World")
|
||||
list = append(list, "Hello")
|
||||
list = append(list, "Apple")
|
||||
|
||||
expected := "Hello,World,Hello,Apple"
|
||||
got := StringListToString(list, ",")
|
||||
if expected != got {
|
||||
t.Errorf("Expected:%s, but got:%s", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntListToString(t *testing.T) {
|
||||
list := make([]int, 0, 4)
|
||||
list = append(list, 1)
|
||||
list = append(list, 2)
|
||||
list = append(list, 3)
|
||||
list = append(list, 4)
|
||||
|
||||
expected := "1,2,3,4"
|
||||
got := IntListToString(list, ",")
|
||||
if expected != got {
|
||||
t.Errorf("Expected:%s, but got:%s", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ListToString(t *testing.T) {
|
||||
list := make([]int64, 0, 4)
|
||||
list = append(list, 1)
|
||||
list = append(list, 2)
|
||||
list = append(list, 3)
|
||||
list = append(list, 4)
|
||||
|
||||
expected := "1,2,3,4"
|
||||
got := Int64ListToString(list, ",")
|
||||
if expected != got {
|
||||
t.Errorf("Expected:%s, but got:%s", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt32ListToString(t *testing.T) {
|
||||
list := make([]int32, 0, 4)
|
||||
list = append(list, 1)
|
||||
list = append(list, 2)
|
||||
list = append(list, 3)
|
||||
list = append(list, 4)
|
||||
|
||||
expected := "1,2,3,4"
|
||||
got := Int32ListToString(list, ",")
|
||||
if expected != got {
|
||||
t.Errorf("Expected:%s, but got:%s", expected, got)
|
||||
}
|
||||
}
|
||||
190
trunk/goutil/stringUtil/transform.go
Normal file
190
trunk/goutil/stringUtil/transform.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 首字母小写
|
||||
func FirstCharToLower(str string) string {
|
||||
if len(str) < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
runeArray := []rune(str)
|
||||
if runeArray[0] >= 65 && runeArray[0] <= 90 {
|
||||
runeArray[0] += 32
|
||||
}
|
||||
return string(runeArray)
|
||||
}
|
||||
|
||||
// 首字母大写
|
||||
func FirstCharToUpper(str string) string {
|
||||
if len(str) < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
runeArray := []rune(str)
|
||||
if runeArray[0] >= 97 && runeArray[0] <= 122 {
|
||||
runeArray[0] -= 32
|
||||
}
|
||||
return string(runeArray)
|
||||
}
|
||||
|
||||
// 将形如1,2|3,4|5,6的字符串转化成map
|
||||
// 返回值:
|
||||
// map[string]string
|
||||
// 错误对象
|
||||
func StringToMap_String_String(str string, seps []string) (data map[string]string, err error) {
|
||||
strList := Split(str, seps)
|
||||
if len(strList) == 0 {
|
||||
err = fmt.Errorf("str is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
if len(strList)%2 != 0 {
|
||||
err = fmt.Errorf("str has odd items.")
|
||||
return
|
||||
}
|
||||
|
||||
data = make(map[string]string, len(strList)/2)
|
||||
for i := 0; i < len(strList); i += 2 {
|
||||
data[strList[i]] = strList[i+1]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 将形如1,2|3,4|5,6的字符串转化成map
|
||||
// 返回值:
|
||||
// map[string]int
|
||||
// 错误对象
|
||||
func StringToMap_String_Int(str string, seps []string) (data map[string]int, err error) {
|
||||
strList := Split(str, seps)
|
||||
if len(strList) == 0 {
|
||||
err = fmt.Errorf("str is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
if len(strList)%2 != 0 {
|
||||
err = fmt.Errorf("str has odd items.")
|
||||
return
|
||||
}
|
||||
|
||||
data = make(map[string]int, len(strList)/2)
|
||||
for i := 0; i < len(strList); i += 2 {
|
||||
key := strList[i]
|
||||
value, err1 := strconv.Atoi(strList[i+1])
|
||||
if err1 != nil {
|
||||
err = fmt.Errorf("Type convertion failed. Value:%s, Error:%v", strList[i+1], err1)
|
||||
return
|
||||
}
|
||||
data[key] = value
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 将形如1,2|3,4|5,6的字符串转化成map
|
||||
// 返回值:
|
||||
// map[int]int
|
||||
// 错误对象
|
||||
func StringToMap_Int_Int(str string, seps []string) (data map[int]int, err error) {
|
||||
strList := Split(str, seps)
|
||||
if len(strList) == 0 {
|
||||
err = fmt.Errorf("str is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
if len(strList)%2 != 0 {
|
||||
err = fmt.Errorf("str has odd items.")
|
||||
return
|
||||
}
|
||||
|
||||
data = make(map[int]int, len(strList)/2)
|
||||
for i := 0; i < len(strList); i += 2 {
|
||||
key, err1 := strconv.Atoi(strList[i])
|
||||
if err1 != nil {
|
||||
err = fmt.Errorf("Type convertion failed. Value:%s, Error:%v", strList[i], err1)
|
||||
return
|
||||
}
|
||||
value, err2 := strconv.Atoi(strList[i+1])
|
||||
if err2 != nil {
|
||||
err = fmt.Errorf("Type convertion failed. Value:%s, Error:%v", strList[i+1], err2)
|
||||
return
|
||||
}
|
||||
data[key] = value
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 将形如1,2|3,4|5,6的字符串转化成map
|
||||
// 返回值:
|
||||
// map[int32]int32
|
||||
// 错误对象
|
||||
func StringToMap_Int32_Int32(str string, seps []string) (data map[int32]int32, err error) {
|
||||
strList := Split(str, seps)
|
||||
if len(strList) == 0 {
|
||||
err = fmt.Errorf("str is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
if len(strList)%2 != 0 {
|
||||
err = fmt.Errorf("str has odd items.")
|
||||
return
|
||||
}
|
||||
|
||||
data = make(map[int32]int32, len(strList)/2)
|
||||
for i := 0; i < len(strList); i += 2 {
|
||||
key, err1 := strconv.Atoi(strList[i])
|
||||
if err1 != nil {
|
||||
err = fmt.Errorf("Type convertion failed. Value:%s, Error:%v", strList[i], err1)
|
||||
return
|
||||
}
|
||||
value, err2 := strconv.Atoi(strList[i+1])
|
||||
if err2 != nil {
|
||||
err = fmt.Errorf("Type convertion failed. Value:%s, Error:%v", strList[i+1], err2)
|
||||
return
|
||||
}
|
||||
data[int32(key)] = int32(value)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 将形如1,2|3,4|5,6的字符串转化成map
|
||||
// 返回值:
|
||||
// map[int32]int64
|
||||
// 错误对象
|
||||
func StringToMap_Int32_Int64(str string, seps []string) (data map[int32]int64, err error) {
|
||||
strList := Split(str, seps)
|
||||
if len(strList) == 0 {
|
||||
err = fmt.Errorf("str is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
if len(strList)%2 != 0 {
|
||||
err = fmt.Errorf("str has odd items.")
|
||||
return
|
||||
}
|
||||
|
||||
data = make(map[int32]int64, len(strList)/2)
|
||||
for i := 0; i < len(strList); i += 2 {
|
||||
key, err1 := strconv.Atoi(strList[i])
|
||||
if err1 != nil {
|
||||
err = fmt.Errorf("Type convertion failed. Value:%s, Error:%v", strList[i], err1)
|
||||
return
|
||||
}
|
||||
|
||||
value, err2 := strconv.ParseInt(strList[i+1], 10, 64)
|
||||
if err2 != nil {
|
||||
err = fmt.Errorf("Type convertion failed. Value:%s, Error:%v", strList[i+1], err2)
|
||||
return
|
||||
}
|
||||
|
||||
data[int32(key)] = value
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
259
trunk/goutil/stringUtil/transform_test.go
Normal file
259
trunk/goutil/stringUtil/transform_test.go
Normal file
@@ -0,0 +1,259 @@
|
||||
package stringUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStringToMap_String_String(t *testing.T) {
|
||||
str := ""
|
||||
seps := []string{",", "|"}
|
||||
data, err := StringToMap_String_String(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3"
|
||||
data, err = StringToMap_String_String(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,5"
|
||||
data, err = StringToMap_String_String(str, seps)
|
||||
if err != nil {
|
||||
t.Errorf("Expected to get no error. But now there is one:%v.", err)
|
||||
return
|
||||
}
|
||||
|
||||
expected := make(map[string]string, 2)
|
||||
expected["1"] = "2"
|
||||
expected["3"] = "5"
|
||||
|
||||
if len(expected) != len(data) {
|
||||
t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data))
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range data {
|
||||
if v1, exists := expected[k]; !exists {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
} else if v != v1 {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringToMap_String_Int(t *testing.T) {
|
||||
str := ""
|
||||
seps := []string{",", "|"}
|
||||
data, err := StringToMap_String_Int(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3"
|
||||
data, err = StringToMap_String_Int(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,abc"
|
||||
data, err = StringToMap_String_Int(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,5"
|
||||
data, err = StringToMap_String_Int(str, seps)
|
||||
if err != nil {
|
||||
t.Errorf("Expected to get no error. But now there is one:%v.", err)
|
||||
return
|
||||
}
|
||||
|
||||
expected := make(map[string]int, 2)
|
||||
expected["1"] = 2
|
||||
expected["3"] = 5
|
||||
|
||||
if len(expected) != len(data) {
|
||||
t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data))
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range data {
|
||||
if v1, exists := expected[k]; !exists {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
} else if v != v1 {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringToMap_Int_Int(t *testing.T) {
|
||||
str := ""
|
||||
seps := []string{",", "|"}
|
||||
data, err := StringToMap_Int_Int(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3"
|
||||
data, err = StringToMap_Int_Int(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,abc"
|
||||
data, err = StringToMap_Int_Int(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|a,3"
|
||||
data, err = StringToMap_Int_Int(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,5"
|
||||
data, err = StringToMap_Int_Int(str, seps)
|
||||
if err != nil {
|
||||
t.Errorf("Expected to get no error. But now there is one:%v.", err)
|
||||
return
|
||||
}
|
||||
|
||||
expected := make(map[int]int, 2)
|
||||
expected[1] = 2
|
||||
expected[3] = 5
|
||||
|
||||
if len(expected) != len(data) {
|
||||
t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data))
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range data {
|
||||
if v1, exists := expected[k]; !exists {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
} else if v != v1 {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringToMap_Int32_Int32(t *testing.T) {
|
||||
str := ""
|
||||
seps := []string{",", "|"}
|
||||
data, err := StringToMap_Int32_Int32(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3"
|
||||
data, err = StringToMap_Int32_Int32(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,abc"
|
||||
data, err = StringToMap_Int32_Int32(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|a,3"
|
||||
data, err = StringToMap_Int32_Int32(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,5"
|
||||
data, err = StringToMap_Int32_Int32(str, seps)
|
||||
if err != nil {
|
||||
t.Errorf("Expected to get no error. But now there is one:%v.", err)
|
||||
return
|
||||
}
|
||||
|
||||
expected := make(map[int32]int32, 2)
|
||||
expected[1] = 2
|
||||
expected[3] = 5
|
||||
|
||||
if len(expected) != len(data) {
|
||||
t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data))
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range data {
|
||||
if v1, exists := expected[k]; !exists {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
} else if v != v1 {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringToMap_Int32_Int64(t *testing.T) {
|
||||
str := ""
|
||||
seps := []string{",", "|"}
|
||||
data, err := StringToMap_Int32_Int64(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3"
|
||||
data, err = StringToMap_Int32_Int64(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|3,abc"
|
||||
data, err = StringToMap_Int32_Int64(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,2|a,3"
|
||||
data, err = StringToMap_Int32_Int64(str, seps)
|
||||
if err == nil {
|
||||
t.Errorf("Expected to get an error. But now there isn't.")
|
||||
return
|
||||
}
|
||||
|
||||
str = "1,36524569852|3,365245698521"
|
||||
data, err = StringToMap_Int32_Int64(str, seps)
|
||||
if err != nil {
|
||||
t.Errorf("Expected to get no error. But now there is one:%v.", err)
|
||||
return
|
||||
}
|
||||
|
||||
expected := make(map[int32]int64, 2)
|
||||
expected[1] = 36524569852
|
||||
expected[3] = 365245698521
|
||||
|
||||
if len(expected) != len(data) {
|
||||
t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data))
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range data {
|
||||
if v1, exists := expected[k]; !exists {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
} else if v != v1 {
|
||||
t.Errorf("data is not equals to expected. %v, %v", expected, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user