Golang非标准字符串排序(数字、混合、版本等)

示例:

  • 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)
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wowhisper

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值