summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Kreen2011-04-12 08:39:38 +0000
committerMarko Kreen2011-04-15 10:20:25 +0000
commit3d8bc13ec1829c530cc79285bc145bd796f8e636 (patch)
treeac44157beb0471aa3a0e6b46d956aeb21040956b
parent32862105dfa922d62c9755ea63658523ad513ee1 (diff)
skytools.natsort: natural sorting of strings
-rw-r--r--python/skytools/natsort.py56
1 files changed, 56 insertions, 0 deletions
diff --git a/python/skytools/natsort.py b/python/skytools/natsort.py
new file mode 100644
index 00000000..059cb58c
--- /dev/null
+++ b/python/skytools/natsort.py
@@ -0,0 +1,56 @@
+"""Natural sort.
+
+Compares numeric parts numerically.
+"""
+
+# Based on idea at http://code.activestate.com/recipes/285264/
+# Works with both Python 2.x and 3.x
+# Ignores leading zeroes: 001 and 01 are considered equal
+
+import re as _re
+_rc = _re.compile(r'\d+|\D+')
+
+def natsort_key(s):
+ """Split string to numeric and non-numeric fragments."""
+ return [ not f[0].isdigit() and f or int(f, 10) for f in _rc.findall(s) ]
+
+def natsort(lst):
+ """Natural in-place sort, case-sensitive."""
+ lst.sort(key = natsort_key)
+
+def natsorted(lst):
+ """Return copy of list, sorted in natural order, case-sensitive.
+
+ >>> natsorted(['ver-1.1', 'ver-1.11', '', 'ver-1.0'])
+ ['', 'ver-1.0', 'ver-1.1', 'ver-1.11']
+ """
+ lst = lst[:]
+ natsort(lst)
+ return lst
+
+# case-insensitive api
+
+def natsort_key_icase(s):
+ """Split string to numeric and non-numeric fragments."""
+ return natsort_key(s.lower())
+
+def natsort_icase(lst):
+ """Natural in-place sort, case-sensitive."""
+ lst.sort(key = natsort_key_icase)
+
+def natsorted_icase(lst):
+ """Return copy of list, sorted in natural order, case-sensitive.
+
+ >>> natsorted_icase(['Ver-1.1', 'vEr-1.11', '', 'veR-1.0'])
+ ['', 'veR-1.0', 'Ver-1.1', 'vEr-1.11']
+ """
+ lst = lst[:]
+ natsort_icase(lst)
+ return lst
+
+
+# run doctest
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
+