Go语言实现有规律的数字版本号的排序工具

 更新时间:2023年01月10日 08:28:14   作者:陈明勇  
这篇文章主要为大家详细介绍了如何利用Go语言实现有规律的数字版本号的排序工具,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下

前言

在某些场景,我们可能需要对版本号进行排序。版本号的形式有很多种,例如:

  • 1.0.0, 1.0.1.1, 2.0.1.1
  • v1.0.0, v1.10.1, v2.0
  • ······

而本文所介绍的版本号排序工具,是针对有规律的数字版本号如 1.0.0, 1, 2.15.0 这种形式。

创作解读

版本号的大小比较与排序

版本号排序的前提,首先得比较两个版本号的大小。由于版本号长度可能不一致,所以需要额外做一些处理。对于版本号的比较,我的算法思路是:

1、以 . 为分隔符,将版本号的每段数字存到切片里,方便后续比较大小。例如 "1.0"["1", "0"]"1.0.1"["1", "0", "1"]

firstVersions := strings.Split(versions[i], ".")
secondVersions := strings.Split(versions[j], ".")

2、由于两个版本号的长度可能不一致,因此需要做 填充0,统一长度 的操作。所以第二步就是获取两个版本号中,最大长度,然后对长度最小的版本号切片,填充零,保持两个版本号的长度一致。例如第一步的两个版本号 ["1", "0"]["1", "0", "1"],需要对第一个版本号填充一个零(填充之后的结果 → ["1", "0", "0"]),才能保持两个版本号的长度一致,方便后续比较。

// 0 填充
// 获取最大长度并向最小长度的切片填充 "0",统一长度
func getMaxAndFillZero(s1 *[]string, s2 *[]string) int {
    len1, len2 := len(*s1), len(*s2)
    if len1 > len2 {
        fillZero(s2, len1-len2)
        return len1
    }
    fillZero(s1, len2-len1)
    return len2
}

// 0 填充
func fillZero(s *[]string, size int) {
    for i := 0; i < size; i++ {
        *s = append(*s, "0")
    }
}

size 为最大长度 - 最小长度的值,也就是要填充 0 的个数。

3、遍历切片,从前依次比较两个版本号每段数字的大小。

如果第一个版本号的第一段数字大于或小于第二个版本号的第二段数字,则可以根据排序规则决定两个版本号的先后位置。

如果相等,则比较下一段数字的大小,以此类推。

for k := 0; k < maxLen; k++ {
    // 由于上面判断了版本号的合法性,因此 error 可以忽略
    vi, _ := strconv.Atoi(firstVersions[k])
    vj, _ := strconv.Atoi(secondVersions[k])
    if vi < vj {
        if sortRule == DESC {
            // 降序排序
            // todo 交换操作
        }
        // 默认升序排序,即使 sortRule 不是 ASC
        // todo 交换操作
    } else if vi > vj {
        // 降序排序
        if sortRule == DESC {
            // todo 交换操作
        }
        // 默认升序排序,即使 sortRule 不是 ASC
        // todo 交换操作
    }
}

对字符串切片的排序,本工具使用的函数是 SliceStable(x any, less func(i, j int) bool),通过此函数,可以自定义比较大小的规则。

sort.SliceStable(versions, func(i, j int) bool {
    firstVersions := strings.Split(versions[i], ".")
    secondVersions := strings.Split(versions[j], ".")
    // 判断版本号格式的合法性
    isNormal(firstVersions)
    isNormal(secondVersions)
    // 获取最大值并填充 "0", 统一长度
    maxLen := getMaxAndFillZero(&firstVersions, &secondVersions)
    for k := 0; k < maxLen; k++ {
        // 由于上面判断了版本号的合法性,因此 error 可以忽略
        vi, _ := strconv.Atoi(firstVersions[k])
        vj, _ := strconv.Atoi(secondVersions[k])
        if vi < vj {
            if sortRule == DESC {
                // 降序排序
                return false
            }
            // 默认升序排序,即使 sortRule 不是 ASC
            return true
        } else if vi > vj {
            // 降序排序
            if sortRule == DESC {
                return true
            }
            // 默认升序排序,即使 sortRule 不是 ASC
            return false
        }
    }
    return false
})

版本号的合法性校验

由于本工具处理的版本号是有规律的数字版本号,如果版本号包含字母或其他特殊字符,会影响到排序的进行,因此需要提前对版本号进行合法性的校验。

// 判断版本号的格式是否合法
func isNormal(versions []string) {
   for _, v := range versions {
      for _, r := range []rune(v) {
         if !unicode.IsNumber(r) {
            panic(errors.New("版本号格式错误:" + string(r)))
         }
      }
   }
}

遍历每段版本号,然后对每段版本号的字符进行遍历,判断是否是数字,如果不是,则 panic 掉,结束排序。

错误处理

由于版本号的不合法性,可能会程序运行的过程中产生错误。因此,有必要人工捕获错误,提高工具的健壮性。

版本号排序函数提供一个 error 的返回值,用于判断是否产生错误。错误的捕获逻辑如下:

defer func() {
   if r := recover(); r != nil {
      if er, ok := r.(error); ok {
         err = er
      } else {
         err = errors.New("")
         fmt.Println("未知错误: ")
         fmt.Println(r)
      }
   }
}()

捕获版本号的合法性校验时主动 panic 的错误,并结束排序。

总结

  • 本工具实现了对有规律的数字版本号集合进行排序。
  • 在排序的过程中,由于版本号的长度可能不一致,因此执行填充 0 操作,统一长度,再进行版本号的大小比较;
  • 除此之外,还对版本号的合法性做了校验,捕获可预知和不可预知的 panic 错误,提高了工具的健壮性。
  • 经测试,核心功能已实现,但有些地方还能改进,后续会对代码进行优化。

到此这篇关于Go语言实现有规律的数字版本号的排序工具的文章就介绍到这了,更多相关Go语言排序工具内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在Golang中正确的修改HTTPRequest的Host的操作方法

    在Golang中正确的修改HTTPRequest的Host的操作方法

    我们工作中经常需要通过HTTP请求Server的服务,比如脚本批量请求接口跑数据,由于一些网关策略,部分Server会要求请求中Header里面附带Host参数,所以本文给大家介绍了如何在Golang中正确的修改HTTPRequest的Host,需要的朋友可以参考下
    2023-12-12
  • Go select使用与底层原理讲解

    Go select使用与底层原理讲解

    这篇文章主要介绍了Go select使用与底层原理讲解,select是Go提供的IO多路复用机制,可以用多个cas同时监听多个channl的读写状态,相关内容需要的朋友可以参考一下
    2022-07-07
  • Go语言中的函数式编程实践

    Go语言中的函数式编程实践

    这篇文章主要介绍了Go语言中的函数式编程实践,主要讲解Go语言中的函数式编程概念和使用。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • Go设计模式之模板方法模式讲解和代码示例

    Go设计模式之模板方法模式讲解和代码示例

    模版方法是一种行为设计模式, 它在基类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤,本文将通过代码示例给大家详细的介绍一下Go模板方法模式,需要的朋友可以参考下
    2023-08-08
  • Golang 并发读写锁的具体实现

    Golang 并发读写锁的具体实现

    Go语言中的sync.RWMutex提供了读写锁机制,允许多个协程并发读取共享资源,但在写操作时保持独占性,本文主要介绍了Golang 并发读写锁的具体实现,感兴趣的可以了解一下
    2025-02-02
  • go语言中int和byte转换方式

    go语言中int和byte转换方式

    这篇文章主要介绍了go语言中int和byte转换方式,需要的朋友可以参考下
    2018-11-11
  • Go语言自定义linter静态检查工具

    Go语言自定义linter静态检查工具

    这篇文章主要介绍了Go语言自定义linter静态检查工具,Go语言是一门编译型语言,编译器将高级语言翻译成机器语言,会先对源代码做词法分析,词法分析是将字符序列转换为Token序列的过程,文章详细介绍需要的小伙伴可以参考一下
    2022-05-05
  • Go生成base64图片验证码实例(超详细工具类)

    Go生成base64图片验证码实例(超详细工具类)

    这段时间需要使用图片验证码库,下面这篇文章主要给大家介绍了关于Go生成base64图片验证码的相关资料,文中给出了详细的实例代码,需要的朋友可以参考下
    2023-06-06
  • golang中的jwt使用教程流程分析

    golang中的jwt使用教程流程分析

    这篇文章主要介绍了golang中的jwt使用教程,接下来我们需要讲解一下Claims该结构体存储了token字符串的超时时间等信息以及在解析时的Token校验工作,需要的朋友可以参考下
    2023-05-05
  • 一文了解Go语言io.Copy函数

    一文了解Go语言io.Copy函数

    这篇文章主要为大家介绍了Go语言io.Copy函数使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07

最新评论