Skip to content

Commit

Permalink
Add naturalsort
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnovak committed Mar 30, 2024
1 parent e61fd13 commit eaa9937
Showing 1 changed file with 112 additions and 0 deletions.
112 changes: 112 additions & 0 deletions src/naturalsort.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import std/algorithm
import std/parseutils
import std/strutils
import std/unicode

import utils

# Original code by Alogani
# From https://github.com/nim-lang/Nim/issues/23462

# {{{ cmpNaturalAscii*()
proc cmpNaturalAscii*(a, b: string): int =
var
ai = 0
bi = 0

while true:
if ai > a.high or bi > b.high:
return a.len - ai - b.len + bi

if not (a[ai].isDigit and b[bi].isDigit):
let diff = cmp(a[ai], b[bi])
if diff != 0:
return diff

inc(ai)
inc(bi)
else:
var
aNum: int
bNum: int
ai += parseInt(a[ai..^1], aNum)
bi += parseInt(b[bi..^1], bNum)

let diff = cmp(aNum, bNum)
if diff != 0:
return diff

# }}}
# {{{ cmpNatural*()
proc cmpNatural*(a, b: seq[Rune]): int =
var
ai = 0
bi = 0

while true:
if ai > a.high or bi > b.high:
return a.len-ai - b.len+bi

if not (a[ai].isDigit and b[bi].isDigit):
let diff = if a[ai] == b[bi]: 0
elif a[ai] <% b[bi]: -1
else: 1
if diff != 0:
return diff

inc(ai)
inc(bi)
else:
var aNum, bNum: int
ai += parseInt($(a[ai..^1]), aNum)
bi += parseInt($(b[bi..^1]), bNum)

let diff = cmp(aNum, bNum)
if diff != 0:
return diff

# }}}
# {{{ cmpNaturalIgnoreCase*()
proc cmpNaturalIgnoreCase*(a, b: seq[Rune]): int =
cmpNatural(a, b)
# }}}

# {{{ naturalSortAscii*()
proc naturalSortAscii*(l: openArray[string]): seq[string] =
l.sorted(cmpNaturalAscii)

# }}}
# {{{ naturalSort*()
proc naturalSort*(l: openArray[seq[Rune]]): seq[seq[Rune]] =
l.sorted(cmpNatural)

proc naturalSort*(l: openArray[string]): seq[string] =
var rl = newSeq[seq[Rune]](l.len)
for i in 0..<l.len:
rl[i] = l[i].toRunes

var sorted = naturalSort(rl)

result = newSeq[string](sorted.len)
for i in 0..<sorted.len:
result[i] = $sorted[i]

# }}}


# {{{ Tests
when isMainModule:
var a = @["d", "a", "cdrom1", "cdrom10", "cdrom102", "cdrom11", "cdrom2",
"cdrom20", "cdrom3", "cdrom30", "cdrom4", "cdrom40", "cdrom100",
"cdrom101", "cdrom103", "cdrom110"]


echo a.naturalSort

var b = @["!a", "[b"]

echo b.naturalSort

# }}}

# vim: et:ts=2:sw=2:fdm=marker

0 comments on commit eaa9937

Please sign in to comment.