Natural order sorting strings with numbers

The following python code makes natural sorting sequences of lexical and numerical values a little easier. It supports any iterable containing strings which have embedded numbers. In short it would give you this:

foo1 < foo2 < foo10

instead of this:

foo1 < foo10 < foo2

As an example, if you have this sequence:

>>> seq = ['foo', 'foo1', 'foo2', 'foo10', 'foobar10', '20', '100', '1', '3', 'bar1']

a regular sort would produce this:

>>> sorted(seq)
['1', '100', '20', '3', 'bar1', 'foo', 'foo1', 'foo10', 'foo2', 'foobar10']

whereas a natural sort would produce this:

>>> natural_sort(seq)
['1', '3', '20', '100', 'bar1', 'foo', 'foo1', 'foo2', 'foo10', 'foobar10']

Here is the code:

import re

def natsort_key(item):
    chunks = re.split('(\d+(?:\.\d+)?)', item)
    for ii in range(len(chunks)):
        if chunks[ii] and chunks[ii][0] in '0123456789':
            if '.' in chunks[ii]: numtype = float
            else: numtype = int
            chunks[ii] = (0, numtype(chunks[ii]))
        else:
            chunks[ii] = (1, chunks[ii])
    return (chunks, item)

def natural_sort(seq):
    sortlist = [item for item in seq]
    sortlist.sort(key=natsort_key)
    return sortlist
Share Comments
comments powered by Disqus