Modules to convert numbers to words in multiple languages with support for 50+ locales.
—
Helper functions that support the core num2words functionality, including currency processing, number manipulation, and Python 2/3 compatibility. These utilities are used internally by the converters but can also be accessed directly for advanced usage.
Functions for parsing and processing currency values with proper decimal handling.
def parse_currency_parts(value, is_int_with_cents=True):
"""
Parse currency value into integer and cents components.
Handles various input types and applies proper rounding for currency precision.
Parameters:
- value: int/float/Decimal/str - Currency value to parse
- is_int_with_cents: bool - Treat integer inputs as cents (default: True)
Returns:
tuple - (integer_part, cents_part, is_negative)
Raises:
ValueError - For invalid currency value formats
"""Usage Examples:
from num2words.currency import parse_currency_parts
# Float parsing with automatic rounding
integer, cents, negative = parse_currency_parts(42.567)
# (42, 57, False) - rounded to nearest cent
# Integer as cents (default behavior)
integer, cents, negative = parse_currency_parts(4250)
# (42, 50, False) - 4250 cents = 42.50 units
# Integer as whole units
integer, cents, negative = parse_currency_parts(42, is_int_with_cents=False)
# (42, 0, False) - 42 whole units, no cents
# String input parsing
integer, cents, negative = parse_currency_parts("42.50")
# (42, 50, False)
integer, cents, negative = parse_currency_parts("-123.45")
# (123, 45, True) - negative flag set
# Decimal precision handling
integer, cents, negative = parse_currency_parts(42.999)
# (43, 0, False) - rounds to nearest cent using ROUND_HALF_UP
# Edge cases
integer, cents, negative = parse_currency_parts(0.01)
# (0, 1, False) - minimum positive value
integer, cents, negative = parse_currency_parts(-0.50)
# (0, 50, True) - negative cents onlyFunctions for manipulating currency form strings with prefixes and adjectives.
def prefix_currency(prefix, base):
"""
Add prefix to currency forms for adjective support.
Parameters:
- prefix: str - Prefix to add (e.g., "European", "American")
- base: tuple - Base currency forms (singular, plural)
Returns:
tuple - Prefixed forms (prefixed_singular, prefixed_plural)
"""Usage Examples:
from num2words.currency import prefix_currency
# Add nationality adjectives
euro_forms = ('euro', 'euros')
prefixed_euro = prefix_currency('European', euro_forms)
# ('European euro', 'European euros')
dollar_forms = ('dollar', 'dollars')
prefixed_dollar = prefix_currency('American', dollar_forms)
# ('American dollar', 'American dollars')
# Use with currency conversion
# These prefixed forms are used when adjective=True in to_currency()Functions for manipulating and splitting number strings.
def splitbyx(n, x, format_int=True):
"""
Split number string into chunks of x digits.
Useful for processing large numbers in groups (e.g., thousands, millions).
Parameters:
- n: str - Number string to split
- x: int - Chunk size (number of digits per chunk)
- format_int: bool - Convert chunks to integers (default: True)
Yields:
int/str - Number chunks from left to right
"""Usage Examples:
from num2words.utils import splitbyx
# Split by thousands (3 digits)
number_str = "1234567890"
chunks = list(splitbyx(number_str, 3))
# [1, 234, 567, 890]
# Split with string preservation
chunks = list(splitbyx(number_str, 3, format_int=False))
# ['1', '234', '567', '890']
# Different chunk sizes
chunks = list(splitbyx("12345678", 4))
# [1234, 5678]
chunks = list(splitbyx("12345678", 2))
# [12, 34, 56, 78]
# Handle numbers shorter than chunk size
chunks = list(splitbyx("123", 5))
# [123] - single chunk when number is shorter
# Real-world usage in number processing
def process_large_number(num_str):
"""Example of using splitbyx for number word generation."""
chunks = list(splitbyx(num_str, 3)) # Split by thousands
# Process each chunk with appropriate scale (thousands, millions, etc.)
return chunksFunctions for extracting and processing individual digits.
def get_digits(n):
"""
Extract last 3 digits of number as reversed list.
Useful for processing hundreds, tens, and units places.
Parameters:
- n: int - Number to extract digits from
Returns:
list - List of last 3 digits in reverse order [units, tens, hundreds]
"""Usage Examples:
from num2words.utils import get_digits
# Basic digit extraction
digits = get_digits(123)
# [3, 2, 1] - units, tens, hundreds
digits = get_digits(45)
# [5, 4, 0] - units, tens, (zero) hundreds
digits = get_digits(7)
# [7, 0, 0] - units, (zero) tens, (zero) hundreds
digits = get_digits(1000)
# [0, 0, 0] - last 3 digits of 1000
digits = get_digits(1234)
# [4, 3, 2] - last 3 digits: 234 reversed
# Usage in number word generation
def process_hundreds(n):
"""Example of using get_digits for word generation."""
units, tens, hundreds = get_digits(n)
words = []
if hundreds:
words.append(f"{digit_words[hundreds]} hundred")
if tens >= 2:
words.append(f"{tens_words[tens]}")
if units:
words.append(f"{digit_words[units]}")
elif tens == 1:
words.append(f"{teens_words[units]}")
elif units:
words.append(f"{digit_words[units]}")
return " ".join(words)Functions for maintaining compatibility between Python 2 and Python 3.
def to_s(val):
"""
Convert value to string with Python 2/3 compatibility.
Handles unicode/str differences between Python versions.
Parameters:
- val: Any - Value to convert to string
Returns:
str/unicode - String representation appropriate for Python version
"""Usage Examples:
from num2words.compat import to_s
# Safe string conversion across Python versions
text = to_s(42) # "42"
text = to_s(42.5) # "42.5"
text = to_s("hello") # "hello"
# Handles unicode properly in both Python 2 and 3
unicode_text = to_s("café") # Proper encoding handling
# Used internally by converters for consistent string handling
def safe_word_join(words):
"""Example internal usage."""
return " ".join(to_s(word) for word in words)Compatibility utilities for string type checking.
# String type compatibility
strtype = basestring # Python 2
strtype = str # Python 3 (when basestring not available)Usage Examples:
from num2words.compat import strtype
# Type checking that works across Python versions
def is_string_input(value):
"""Check if input is a string type."""
return isinstance(value, strtype)
# Example usage in validation
def validate_input(value):
"""Validate input type for conversion."""
if is_string_input(value):
# Handle string input
return float(value)
elif isinstance(value, (int, float)):
# Handle numeric input
return value
else:
raise TypeError(f"Unsupported input type: {type(value)}")High-precision decimal operations used in currency conversion.
# Decimal rounding modes
from decimal import ROUND_HALF_UP, Decimal
# Used internally for currency precision
def quantize_currency(value):
"""Round currency value to 2 decimal places."""
return Decimal(str(value)).quantize(
Decimal('.01'),
rounding=ROUND_HALF_UP
)Usage Examples:
from decimal import Decimal, ROUND_HALF_UP
# Precise currency rounding (used internally)
value = Decimal('42.567')
rounded = value.quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
# Decimal('42.57')
# Handle edge cases in rounding
value = Decimal('42.565')
rounded = value.quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
# Decimal('42.57') - rounds up at .5
value = Decimal('42.564')
rounded = value.quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
# Decimal('42.56') - rounds down below .5Utilities used internally by the converter classes.
# Number component processing
def split_currency_components(value):
"""Split currency value maintaining precision."""
if isinstance(value, int):
# Assume cents if integer
negative = value < 0
value = abs(value)
integer, cents = divmod(value, 100)
else:
# Handle float/Decimal with rounding
value = Decimal(str(value))
value = value.quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
negative = value < 0
value = abs(value)
integer, fraction = divmod(value, 1)
cents = int(fraction * 100)
return int(integer), cents, negative
# String cleaning and normalization
def normalize_number_string(num_str):
"""Clean and normalize number string input."""
# Remove common formatting characters
cleaned = num_str.replace(',', '').replace(' ', '')
# Handle negative signs
if cleaned.startswith('-'):
return '-', cleaned[1:]
else:
return '', cleanedCombining utilities for custom number processing.
from num2words.utils import splitbyx, get_digits
from num2words.currency import parse_currency_parts
from num2words.compat import to_s
def custom_number_processor(value):
"""Example of combining utilities for custom processing."""
# Parse as currency to get components
integer, cents, negative = parse_currency_parts(value)
# Process large integer part in chunks
if integer >= 1000:
int_str = str(integer)
chunks = list(splitbyx(int_str, 3))
# Process each chunk with scale words
else:
# Process as simple hundreds
digits = get_digits(integer)
# Process individual digits
# Convert components to strings safely
result_parts = [to_s(part) for part in processed_parts]
return " ".join(result_parts)
# Error handling with utilities
def safe_parse_currency(value):
"""Safely parse currency with error handling."""
try:
return parse_currency_parts(value)
except (ValueError, TypeError) as e:
# Handle parsing errors gracefully
return 0, 0, FalseThese utilities integrate seamlessly with the main num2words functionality:
# Internal usage in num2words function
def num2words(number, **kwargs):
# String input handling
if isinstance(number, strtype):
number = converter.str_to_number(number)
# Currency processing
if kwargs.get('to') == 'currency':
integer, cents, negative = parse_currency_parts(number)
return converter.to_currency(number, **kwargs)
# Standard number processing with utilities
return converter.to_cardinal(number)Utility functions provide robust error handling:
# Currency parsing errors
try:
parse_currency_parts("invalid_number")
except ValueError as e:
print(f"Invalid currency format: {e}")
# String conversion errors
try:
result = to_s(complex_object)
except Exception as e:
print(f"String conversion failed: {e}")
# Safe utility usage with fallbacks
def safe_split_number(num_str, chunk_size):
"""Safely split number string with error handling."""
try:
return list(splitbyx(num_str, chunk_size))
except (ValueError, TypeError):
# Fallback to character-based splitting
return [num_str[i:i+chunk_size] for i in range(0, len(num_str), chunk_size)]Install with Tessl CLI
npx tessl i tessl/pypi-num2words