102 lines
1.9 KiB
Go
102 lines
1.9 KiB
Go
package web
|
||
|
||
import (
|
||
"sort"
|
||
"strings"
|
||
|
||
"gitea.kazu634.com/kazu634/tver/internal/store"
|
||
)
|
||
|
||
func sortJobsNaturally(jobs []store.Job) {
|
||
sort.SliceStable(jobs, func(i, j int) bool {
|
||
if comparison := compareNaturalTitle(jobs[i].Title, jobs[j].Title); comparison != 0 {
|
||
return comparison < 0
|
||
}
|
||
left, right := jobs[i].FinishedAt, jobs[j].FinishedAt
|
||
if left == nil || right == nil {
|
||
if left != right {
|
||
return left == nil
|
||
}
|
||
} else if !left.Equal(*right) {
|
||
return left.Before(*right)
|
||
}
|
||
return jobs[i].ID < jobs[j].ID
|
||
})
|
||
}
|
||
|
||
func compareNaturalTitle(left, right string) int {
|
||
a, b := []rune(left), []rune(right)
|
||
ai, bi := 0, 0
|
||
for ai < len(a) && bi < len(b) {
|
||
_, aIsDigit := decimalDigit(a[ai])
|
||
_, bIsDigit := decimalDigit(b[bi])
|
||
if aIsDigit && bIsDigit {
|
||
var an, bn strings.Builder
|
||
for ai < len(a) {
|
||
digit, ok := decimalDigit(a[ai])
|
||
if !ok {
|
||
break
|
||
}
|
||
an.WriteByte(byte('0' + digit))
|
||
ai++
|
||
}
|
||
for bi < len(b) {
|
||
digit, ok := decimalDigit(b[bi])
|
||
if !ok {
|
||
break
|
||
}
|
||
bn.WriteByte(byte('0' + digit))
|
||
bi++
|
||
}
|
||
if comparison := compareDecimal(an.String(), bn.String()); comparison != 0 {
|
||
return comparison
|
||
}
|
||
continue
|
||
}
|
||
if a[ai] < b[bi] {
|
||
return -1
|
||
}
|
||
if a[ai] > b[bi] {
|
||
return 1
|
||
}
|
||
ai++
|
||
bi++
|
||
}
|
||
if ai == len(a) && bi < len(b) {
|
||
return -1
|
||
}
|
||
if bi == len(b) && ai < len(a) {
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func decimalDigit(r rune) (int, bool) {
|
||
switch {
|
||
case '0' <= r && r <= '9':
|
||
return int(r - '0'), true
|
||
case '0' <= r && r <= '9':
|
||
return int(r - '0'), true
|
||
default:
|
||
return 0, false
|
||
}
|
||
}
|
||
|
||
func compareDecimal(left, right string) int {
|
||
left = strings.TrimLeft(left, "0")
|
||
right = strings.TrimLeft(right, "0")
|
||
if left == "" {
|
||
left = "0"
|
||
}
|
||
if right == "" {
|
||
right = "0"
|
||
}
|
||
if len(left) < len(right) {
|
||
return -1
|
||
}
|
||
if len(left) > len(right) {
|
||
return 1
|
||
}
|
||
return strings.Compare(left, right)
|
||
}
|