CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-natsort

Simple yet flexible natural sorting in Python that enables developers to sort strings containing numbers in a natural, human-expected order rather than lexicographical order.

Pending
Overview
Eval results
Files

algorithm-configuration.mddocs/

Algorithm Configuration

The ns enum system provides fine-grained control over natural sorting behavior. Options can be combined using bitwise OR operations to create customized sorting algorithms that handle different data types and cultural conventions.

Capabilities

Core ns Enum Class

The main configuration enum that controls natsort algorithm behavior.

class ns(enum.IntEnum):
    """
    Enum to control the natsort algorithm.
    
    Options can be combined using bitwise OR (|) operations.
    Each option has a shortened 1- or 2-letter form.
    """
    
    # Number interpretation (mutually exclusive groups)
    DEFAULT = 0                    # Default behavior
    INT = I = 0                   # Parse numbers as integers (default)
    UNSIGNED = U = 0              # Ignore signs like +/- (default)
    FLOAT = F = 1                 # Parse numbers as floats
    SIGNED = S = 2                # Consider +/- signs in numbers
    REAL = R = 3                  # Shortcut for FLOAT | SIGNED
    NOEXP = N = 4                 # Don't parse scientific notation (e.g., 1e4)
    
    # String and character handling
    IGNORECASE = IC = 64          # Case-insensitive sorting
    LOWERCASEFIRST = LF = 128     # Lowercase letters before uppercase
    GROUPLETTERS = G = 256        # Group upper/lowercase together
    CAPITALFIRST = C = 512        # Capitalized words first (alias: UNGROUPLETTERS)
    UNGROUPLETTERS = UG = 512     # Alias for CAPITALFIRST
    
    # Locale and internationalization
    LOCALEALPHA = LA = 16         # Locale-aware alphabetical sorting only
    LOCALENUM = LN = 32           # Locale-aware numeric formatting only
    LOCALE = L = 48               # Locale-aware sorting (LOCALEALPHA | LOCALENUM)
    
    # Special handling
    PATH = P = 8                  # Treat strings as filesystem paths
    NANLAST = NL = 1024           # Place NaN values last instead of first
    COMPATIBILITYNORMALIZE = CN = 2048  # Use NFKD unicode normalization
    NUMAFTER = NA = 4096          # Sort numbers after non-numbers
    PRESORT = PS = 8192           # Pre-sort as strings before natural sorting

Algorithm Type Alias

Type definition for algorithm specifications.

NSType = Union[ns, int]
"""
Type alias for algorithm specification.
Accepts either ns enum values or integer combinations.
"""

Usage Examples

Basic Number Handling Options

from natsort import natsorted, ns

# Default integer handling
data = ['item1', 'item10', 'item2']
print(natsorted(data))  # ['item1', 'item2', 'item10']

# Float number handling
float_data = ['value1.5', 'value1.10', 'value1.05']
print(natsorted(float_data, alg=ns.FLOAT))
# Output: ['value1.05', 'value1.5', 'value1.10']

# Signed number handling (positive and negative)
signed_data = ['temp-5', 'temp10', 'temp-12', 'temp2']
print(natsorted(signed_data, alg=ns.SIGNED))
# Output: ['temp-12', 'temp-5', 'temp2', 'temp10']

# Real numbers (float + signed)
real_data = ['val-1.5', 'val2.3', 'val-0.8', 'val10.1']
print(natsorted(real_data, alg=ns.REAL))
# Output: ['val-1.5', 'val-0.8', 'val2.3', 'val10.1']

Case Sensitivity Options

from natsort import natsorted, ns

mixed_case = ['Item1', 'item10', 'Item2', 'item20']

# Default (case-sensitive)
print("Default:", natsorted(mixed_case))
# Output: ['Item1', 'Item2', 'item10', 'item20']

# Case-insensitive
print("Ignore case:", natsorted(mixed_case, alg=ns.IGNORECASE))
# Output: ['Item1', 'Item2', 'item10', 'item20']

# Lowercase first
print("Lowercase first:", natsorted(mixed_case, alg=ns.LOWERCASEFIRST))
# Output: ['item10', 'item20', 'Item1', 'Item2']

# Group letters (case-insensitive grouping)
print("Group letters:", natsorted(mixed_case, alg=ns.GROUPLETTERS))
# Output: ['Item1', 'item10', 'Item2', 'item20']

Path-Specific Sorting

from natsort import natsorted, ns

# File paths with different extensions and directories
paths = [
    'folder/file10.txt',
    'folder/file2.txt', 
    'folder/file1.log',
    'folder/file10.log',
    'folder/file2.py'
]

# Default sorting
print("Default sorting:")
for path in natsorted(paths):
    print(f"  {path}")

# Path-aware sorting (splits on separators and extensions)
print("\nPath-aware sorting:")
for path in natsorted(paths, alg=ns.PATH):
    print(f"  {path}")

Locale-Aware Sorting

from natsort import natsorted, ns

# International characters and accents
international = ['café', 'naïve', 'résumé', 'Åpfel', 'zebra', 'Zürich']

# Default sorting (ASCII order)
print("Default:", natsorted(international))

# Locale-aware sorting (requires proper locale setup)
print("Locale-aware:", natsorted(international, alg=ns.LOCALE))

# Locale-aware with case insensitive
print("Locale + ignore case:", 
      natsorted(international, alg=ns.LOCALE | ns.IGNORECASE))

# Note: Results depend on system locale configuration
# Install PyICU for best locale support

Advanced Algorithm Combinations

from natsort import natsorted, ns

# Scientific data with complex requirements
scientific_data = [
    'Sample-1.5E+3_Trial2',
    'sample-2.1e-4_trial10', 
    'SAMPLE-0.8E+2_trial1',
    'Sample-3.2_Trial20'
]

# Combine multiple options:
# - REAL: handle signed floats and scientific notation  
# - IGNORECASE: case-insensitive comparison
# - LOWERCASEFIRST: lowercase variants come first
combined_alg = ns.REAL | ns.IGNORECASE | ns.LOWERCASEFIRST

sorted_scientific = natsorted(scientific_data, alg=combined_alg)
print("Scientific data with combined algorithm:")
for item in sorted_scientific:
    print(f"  {item}")

Special Value Handling

from natsort import natsorted, ns
import math

# Data with special values
data_with_nan = ['value1', 'value10', None, 'value2', float('nan')]

# Default NaN handling (NaN comes first)
print("Default NaN handling:", natsorted(data_with_nan))

# NaN last
print("NaN last:", natsorted(data_with_nan, alg=ns.NANLAST))

# Numbers after non-numbers (reverse typical order)
mixed_types = ['abc', '10', 'def', '2', 'ghi']
print("Default:", natsorted(mixed_types))
print("Numbers after:", natsorted(mixed_types, alg=ns.NUMAFTER))

Pre-sorting for Consistency

from natsort import natsorted, ns

# Data where string representation affects order
inconsistent_data = ['a01', 'a1', 'a10', 'a010']

# Default behavior (may be inconsistent due to string representation)
print("Default:", natsorted(inconsistent_data))

# Pre-sort to ensure consistent ordering
print("With presort:", natsorted(inconsistent_data, alg=ns.PRESORT))

Unicode Normalization

from natsort import natsorted, ns

# Unicode characters that may have different representations
unicode_data = ['café', 'cafe\u0301']  # Second has combining accent

# Default normalization (NFD)
print("Default normalization:", natsorted(unicode_data))

# Compatibility normalization (NFKD) - converts more characters
print("Compatibility normalization:", 
      natsorted(unicode_data, alg=ns.COMPATIBILITYNORMALIZE))

Building Complex Algorithms

from natsort import natsorted, ns

def create_algorithm(**options):
    """Helper function to build algorithm from named options."""
    alg = ns.DEFAULT
    
    if options.get('float_numbers'):
        alg |= ns.FLOAT
    if options.get('signed_numbers'):
        alg |= ns.SIGNED
    if options.get('ignore_case'):
        alg |= ns.IGNORECASE
    if options.get('locale_aware'):
        alg |= ns.LOCALE
    if options.get('path_sorting'):
        alg |= ns.PATH
    if options.get('numbers_last'):
        alg |= ns.NUMAFTER
        
    return alg

# Example usage of algorithm builder
data = ['File-1.5', 'file10.2', 'FILE2.0']

# Build custom algorithm
custom_alg = create_algorithm(
    float_numbers=True,
    signed_numbers=True, 
    ignore_case=True
)

result = natsorted(data, alg=custom_alg)
print(f"Custom algorithm result: {result}")

# Equivalent to:
# result = natsorted(data, alg=ns.REAL | ns.IGNORECASE)

Platform-Specific Considerations

from natsort import natsorted, ns
import sys

# Algorithm selection based on platform/locale
def get_platform_algorithm():
    """Select appropriate algorithm based on platform."""
    base_alg = ns.REAL | ns.IGNORECASE
    
    if sys.platform.startswith('win'):
        # Windows-specific adjustments
        return base_alg | ns.LOWERCASEFIRST
    else:
        # Unix-like systems
        return base_alg | ns.LOCALE
        
platform_alg = get_platform_algorithm()
data = ['File1', 'file10', 'File2']
result = natsorted(data, alg=platform_alg)
print(f"Platform-optimized result: {result}")

Install with Tessl CLI

npx tessl i tessl/pypi-natsort

docs

algorithm-configuration.md

core-sorting.md

index-sorting.md

index.md

key-generation.md

utilities.md

tile.json