github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/common/naturalsort.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "fmt" 8 "sort" 9 "strconv" 10 "strings" 11 "unicode" 12 ) 13 14 // SortStringsNaturally sorts strings according to their natural sort order. 15 func SortStringsNaturally(s []string) []string { 16 sort.Sort(naturally(s)) 17 return s 18 } 19 20 type naturally []string 21 22 func (n naturally) Len() int { 23 return len(n) 24 } 25 26 func (n naturally) Swap(a, b int) { 27 n[a], n[b] = n[b], n[a] 28 } 29 30 // Less sorts by non-numeric prefix and numeric suffix 31 // when one exists. 32 func (n naturally) Less(a, b int) bool { 33 aPrefix, aNumber := splitAtNumber(n[a]) 34 bPrefix, bNumber := splitAtNumber(n[b]) 35 if aPrefix == bPrefix { 36 return aNumber < bNumber 37 } 38 return n[a] < n[b] 39 } 40 41 // splitAtNumber splits given string into prefix and numeric suffix. 42 // If no numeric suffix exists, full original string is returned as 43 // prefix with -1 as a suffix. 44 func splitAtNumber(str string) (string, int) { 45 i := strings.LastIndexFunc(str, func(r rune) bool { 46 return !unicode.IsDigit(r) 47 }) + 1 48 if i == len(str) { 49 // no numeric suffix 50 return str, -1 51 } 52 n, err := strconv.Atoi(str[i:]) 53 if err != nil { 54 panic(fmt.Sprintf("parsing number %v: %v", str[i:], err)) // should never happen 55 } 56 return str[:i], n 57 }