natural sorting
string processing
alphanumeric sorting
user-friendly sorting
programming tips

Sorting strings containing numbers in a user friendly way

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Users expect file2.txt to appear before file10.txt, but default string sorting usually does the opposite. That is because ordinary lexicographic sorting compares characters one by one instead of treating embedded digit runs as actual numbers.

Lexicographic Sort vs Natural Sort

A normal string sort compares text like this:

  • 'file1'
  • 'file10'
  • 'file2'

That result is technically correct for character-by-character comparison, because '1' comes before '2'. A user-friendly sort, often called natural sort, splits each string into text parts and numeric parts so 10 is compared as the number ten rather than the characters '1' and '0'.

A Simple Python Key Function

One common approach is to split each string into alternating text and digit chunks, convert digit chunks to integers, and use the resulting list as the sort key.

python
1import re
2
3
4def natural_key(value):
5    parts = re.split(r"(\d+)", value)
6    key = []
7
8    for part in parts:
9        if part.isdigit():
10            key.append(int(part))
11        else:
12            key.append(part.casefold())
13
14    return key
15
16
17items = ["img10.png", "img2.png", "img1.png"]
18print(sorted(items, key=natural_key))

Output:

text
['img1.png', 'img2.png', 'img10.png']

The important detail is that the key contains integers for numeric chunks and lowercase text for alphabetic chunks.

Why casefold() Helps

Natural sorting is often expected to be case-insensitive as well. Using casefold() instead of lower() is a stronger normalization choice for Unicode text.

python
items = ["File2", "file10", "file1"]
print(sorted(items, key=natural_key))

That produces a more user-friendly order than a raw case-sensitive comparison.

Handling More Complex Names

Real filenames and labels often include multiple numeric segments.

python
1items = [
2    "chapter2-section10",
3    "chapter2-section2",
4    "chapter10-section1",
5]
6
7print(sorted(items, key=natural_key))

Because the key breaks each string into alternating chunks, it naturally compares chapter2 before chapter10 and then compares section numbers within matching prefixes.

Libraries vs Custom Code

If natural sorting is a core feature in your application, a dedicated library can save time. In Python, the natsort package handles many edge cases around signs, decimals, and locale-aware behavior. A custom regex-based key is still a solid choice when you only need the common integer-in-string case and want a dependency-free solution.

The tradeoff is control versus completeness. Your own key function is easy to inspect. A mature library usually handles more corner cases.

Decide What “User Friendly” Means

Natural sorting is not one universal rule. Different products want different behavior:

  • case-sensitive or case-insensitive ordering
  • integers only or decimals too
  • locale-aware text comparison or binary comparison
  • treatment of leading zeros such as item02

That is why a custom key often becomes the right answer. You define the behavior your users actually expect instead of assuming one canned rule fits every list.

Common Pitfalls

  • Using plain string sorting and expecting embedded numbers to behave numerically is the root problem.
  • Forgetting case normalization can make otherwise natural results feel inconsistent.
  • Converting every digit sequence blindly may not be right if the numbers are version segments, identifiers, or codes with leading-zero semantics.
  • Assuming one regex handles decimals, negatives, and localized numbers can lead to subtle bugs.
  • Reimplementing a full-featured natural sort from scratch is unnecessary if a well-tested library already matches the requirement.

Summary

  • Default string sorting is lexicographic, not numeric-aware.
  • Natural sorting works by splitting strings into text and numeric parts.
  • A regex-based key function is a clean solution for many common cases.
  • 'casefold() improves user-friendly ordering for mixed-case text.'
  • Define the exact behavior you want, because natural sorting requirements vary by product.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.