示例:
-
v9.0.22
-
01、你好啊
-
200、300、500
-
aaaa3、Bcd2
代码:
package main
import (
"fmt"
"sort"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
type Test struct {
Name string
Type string
}
// SortStructsByValueWithNumbers 对包含数字的字符串结构体切片进行排序
func SortStructsByValueWithNumbers(structs []Test) {
// 自定义排序函数
sort.Slice(structs, func(i, j int) bool {
a := structs[i].Name
b := structs[j].Name
// 1、首先比较 Type 字段
if structs[i].Type == "dir" && structs[j].Type == "file" {
return true
} else if structs[i].Type == "file" && structs[j].Type == "dir" {
return false
}
// 2、处理字符串完全为数字的排序:123 456 789
if isStringNumeric(a) {
return toInt(a) < toInt(b)
}
// 3、处理首字符串为数字排序:1.你好 2.真的
if isFirstCharDigit(a) {
// 非数字字符,按照自定义的compare函数比较字符串
return compare(a, b)
}
// 4、处理中文按长度排序: 你好吗 你好 大家好
if isChineseChar(a) {
return utf8.RuneCountInString(a) < utf8.RuneCountInString(b)
}
// 5、使用自定义的compare函数比较字符串:逐个字符比较可兼容非标准字符串(如:v9.10.3.a)
return compare(a, b)
})
}
// 比较两个字符串
func compare(a, b string) bool {
i := 0
j := 0
for i < len(a) && j < len(b) {
// 提取a和b的下一个片段
aPart, aNum, aLen := extract(a[i:])
bPart, bNum, bLen := extract(b[j:])
// 如果片段相等,比较数字部分(如果存在)
if aPart == bPart {
if aNum != bNum {
return aNum < bNum
}
} else {
// 比较字符串片段
return strings.ToLower(aPart) < strings.ToLower(bPart)
}
// 移动到下一个片段
i += aLen
j += bLen
}
// 如果一个字符串是另一个字符串的前缀,那么较短的应该排在前面
return len(a) < len(b)
}
// 提取字符串的下一个片段和数字(如果存在)
func extract(s string) (string, int, int) {
i := 0
for i < len(s) && (s[i] < '0' || s[i] > '9') {
i++
}
j := i
for j < len(s) && s[j] >= '0' && s[j] <= '9' {
j++
}
// 如果没有找到数字部分,返回整个字符串
if i == 0 && j == len(s) {
return s, 0, len(s)
}
// 否则,返回非数字部分和数字
return s[:i], toInt(s[i:j]), j
}
// 将字符串转换为整数
func toInt(s string) int {
num, _ := strconv.Atoi(s)
return num
}
// IsChineseChar 判断字符串是否包含中文字符
func isChineseChar(str string) bool {
for _, r := range str {
if unicode.Is(unicode.Scripts["Han"], r) {
return true
}
}
return false
}
// 判断字符串的字符串是否是数字的方法
func isStringNumeric(s string) bool {
_, err := strconv.Atoi(s) // 尝试将字符串转换为整数
// 如果没有错误,说明字符串是数字
return err == nil
}
// 判断字符串的第一个字符是否是数字的方法
func isFirstCharDigit(str string) bool {
if len(str) == 0 {
return false // 空字符串不包含数字字符
}
firstChar := rune(str[0])
return unicode.IsDigit(firstChar)
}
func main() {
//"v9.0.22", "阿訇", "v9.10.0", "v9.5.0", "bcd2", "bcd1", "abc10", "PE", "Virtio", "Ec2config", "你好弟弟"
string := []Test{
{
Name: "v9.0.22",
Type: "dir",
}, {
Name: "v9.10.0",
Type: "dir",
}, {
Name: "v9.5.0",
Type: "dir",
}, {
Name: "Bcd2",
Type: "file",
}, {
Name: "你好弟弟",
Type: "file",
}, {
Name: "02、阿訇",
Type: "file",
}, {
Name: "01、弟弟第",
Type: "file",
}, {
Name: "aaaa3",
Type: "file",
}, {
Name: "10",
Type: "file",
}, {
Name: "200",
Type: "file",
}, {
Name: "300",
Type: "file",
}, {
Name: "7",
Type: "file",
},
}
// 使用排序函数进行排序
SortStructsByValueWithNumbers(string)
// 打印排序后的结果
for _, str := range string {
fmt.Println(str)
}
}