Go語言實現(xiàn)有規(guī)律的數(shù)字版本號的排序工具
前言
在某些場景,我們可能需要對版本號進行排序。版本號的形式有很多種,例如:
- 1.0.0, 1.0.1.1, 2.0.1.1
- v1.0.0, v1.10.1, v2.0
- ······
而本文所介紹的版本號排序工具,是針對有規(guī)律的數(shù)字版本號如 1.0.0, 1, 2.15.0 這種形式。
創(chuàng)作解讀
版本號的大小比較與排序
版本號排序的前提,首先得比較兩個版本號的大小。由于版本號長度可能不一致,所以需要額外做一些處理。對于版本號的比較,我的算法思路是:
1、以 .
為分隔符,將版本號的每段數(shù)字存到切片里,方便后續(xù)比較大小。例如 "1.0"
→ ["1", "0"]
,"1.0.1"
→ ["1", "0", "1"]
。
firstVersions := strings.Split(versions[i], ".") secondVersions := strings.Split(versions[j], ".")
2、由于兩個版本號的長度可能不一致,因此需要做 填充0,統(tǒng)一長度
的操作。所以第二步就是獲取兩個版本號中,最大長度,然后對長度最小的版本號切片,填充零,保持兩個版本號的長度一致。例如第一步的兩個版本號 ["1", "0"]
、["1", "0", "1"]
,需要對第一個版本號填充一個零(填充之后的結(jié)果 → ["1", "0", "0"]
),才能保持兩個版本號的長度一致,方便后續(xù)比較。
// 0 填充 // 獲取最大長度并向最小長度的切片填充 "0",統(tǒng)一長度 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
的個數(shù)。
3、遍歷切片,從前依次比較兩個版本號每段數(shù)字的大小。
如果第一個版本號的第一段數(shù)字大于或小于第二個版本號的第二段數(shù)字,則可以根據(jù)排序規(guī)則決定兩個版本號的先后位置。
如果相等,則比較下一段數(shù)字的大小,以此類推。
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 交換操作 } }
對字符串切片的排序,本工具使用的函數(shù)是 SliceStable(x any, less func(i, j int) bool)
,通過此函數(shù),可以自定義比較大小的規(guī)則。
sort.SliceStable(versions, func(i, j int) bool { firstVersions := strings.Split(versions[i], ".") secondVersions := strings.Split(versions[j], ".") // 判斷版本號格式的合法性 isNormal(firstVersions) isNormal(secondVersions) // 獲取最大值并填充 "0", 統(tǒng)一長度 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 })
版本號的合法性校驗
由于本工具處理的版本號是有規(guī)律的數(shù)字版本號,如果版本號包含字母或其他特殊字符,會影響到排序的進行,因此需要提前對版本號進行合法性的校驗。
// 判斷版本號的格式是否合法 func isNormal(versions []string) { for _, v := range versions { for _, r := range []rune(v) { if !unicode.IsNumber(r) { panic(errors.New("版本號格式錯誤:" + string(r))) } } } }
遍歷每段版本號,然后對每段版本號的字符進行遍歷,判斷是否是數(shù)字,如果不是,則 panic
掉,結(jié)束排序。
錯誤處理
由于版本號的不合法性,可能會程序運行的過程中產(chǎn)生錯誤。因此,有必要人工捕獲錯誤,提高工具的健壯性。
版本號排序函數(shù)提供一個 error
的返回值,用于判斷是否產(chǎn)生錯誤。錯誤的捕獲邏輯如下:
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
的錯誤,并結(jié)束排序。
總結(jié)
- 本工具實現(xiàn)了對有規(guī)律的數(shù)字版本號集合進行排序。
- 在排序的過程中,由于版本號的長度可能不一致,因此執(zhí)行填充
0
操作,統(tǒng)一長度,再進行版本號的大小比較; - 除此之外,還對版本號的合法性做了校驗,捕獲可預知和不可預知的
panic
錯誤,提高了工具的健壯性。 - 經(jīng)測試,核心功能已實現(xiàn),但有些地方還能改進,后續(xù)會對代碼進行優(yōu)化。
到此這篇關(guān)于Go語言實現(xiàn)有規(guī)律的數(shù)字版本號的排序工具的文章就介紹到這了,更多相關(guān)Go語言排序工具內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang解析json數(shù)據(jù)的4種方法總結(jié)
在日常工作中每一名開發(fā)者,不管是前端還是后端,都經(jīng)常使用 JSON,下面這篇文章主要給大家介紹了關(guān)于golang解析json數(shù)據(jù)的4種方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06golang elasticsearch Client的使用詳解
這篇文章主要介紹了golang elasticsearch Client的使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-05-05