Преобразование цифр в словесную форму: методы Python
Преобразование чисел в текст на Python
Часто в приложениях требуется представить число прописью: в бухгалтерских отчётах, договорах, квитанциях или просто для улучшения читаемости. Python предлагает несколько способов - от простых библиотек до полностью ручных решений. Выбор зависит от требуемой точности, поддержки падежей и объёма обрабатываемых чисел. Рассмотрим наиболее эффективные и альтернативные подходы.
Как быстро преобразовать число в текст на русском языке с помощью готовой библиотеки?
Самый простой и надёжный путь - использовать библиотеку num2words. Она поддерживает множество языков, включая русский, и правильно обрабатывает склонения, роды и большие числа (до 10^66). Установка через pip:
pip install num2wordsввод через пробел python (ввод и вывод чисел через пробел в python)
Пример использования:
from num2words import num2words
print(num2words(12345, lang='ru'))вывод через пробел python (вывод через пробел в python)
двенадцать тысяч триста сорок пять
Python print sep (параметр sep в print python)
Функция num2words принимает число и параметр lang. Дополнительно можно указать to='currency' для денежных сумм, ordinal=True для порядковых числительных.
Возможные проблемы
- Неверный регистр: библиотека выводит текст в нижнем регистре. Если требуется заглавная буква в начале строки, нужно применить capitalize().
- Отсутствие поддержки некоторых валют: для денежного формата нужно указать код валюты (например, currency='RUB').
- Большие числа могут быть обработаны, но при длине более 66 разрядов (секстиллионов) возникнет ошибка.
Как написать собственную функцию преобразования числа в текст без внешних библиотек?
Если нельзя устанавливать сторонние пакеты, можно реализовать алгоритм вручную. Основная идея - разбить число на разряды (единицы, десятки, сотни, тысячи, миллионы и т.д.) и сопоставить каждому разряду слова из заранее подготовленных словарей. Пример для чисел до 999 999 999:
def число_прописью(число):
единицы = ['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять']
десятки = ['', 'десять', 'двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто']
сотни = ['', 'сто', 'двести', 'триста', 'четыреста', 'пятьсот', 'шестьсот', 'семьсот', 'восемьсот', 'девятьсот']
# ... полное определение словарей опущено для краткости
return результатPython форматирование чисел (форматирование чисел при выводе в python)
Подробная реализация потребует учёта склонений (например, для тысяч: 'тысяча', 'тысячи', 'тысяч') и особых форм для чисел 10-19. Ошибки часто возникают из-за неверного согласования родов и чисел (например, 'два рубля' vs 'две тысячи').
Типичные ошибки ручной реализации
- Пропуск слова для нулевого разряда.
- Неправильное склонение тысяч: 'одна тысяча' (женский род) для 1, но 'две тысячи' для 2.
- Некорректное формирование чисел от 11 до 19: они должны использовать особые формы ('одиннадцать', 'двенадцать'...).
Как учесть падежи и роды при выводе числа прописью с помощью pymorphy2?
Библиотека pymorphy2 предназначена для морфологического анализа русских слов. Её можно использовать для склонения числительных в нужный падеж (родительный, дательный и т.д.). Например, требуется вывести число в родительном падеже: 'пятьсот рублей' -> 'пятисот рублей'.
import pymorphy2
morph = pymorphy2.MorphAnalyzer()
# преобразование числа в пропись (через num2words) и затем склонение
from num2words import num2words
text = num2words(500, lang='ru')
# разбиваем на слова и склоняем каждое
words = text.split()
inflected = [morph.parse(w)[0].inflect({'gent'}).word for w in words]
print(' '.join(inflected))формат вывода строки python (формат вывода строки в python)
пятисот
список без скобок python (вывод списка без скобок в python)
Этот подход более гибкий, но требует дополнительной обработки (выбор правильной парадигмы для каждого слова). Основная проблема - числительные могут быть не распознаны pymorphy2 как одно слово, например 'двадцать' будет разобрано, а 'двадцать один' - как два слова. Рекомендуется склонять только числительные, а существительные (рубли, копейки) - отдельно.
Проблемы с pymorphy2
- Нужно загрузить словарь (примерно 10–20 МБ).
- Склонение составных числительных (от 21 и выше) может требовать разбора каждого компонента.
- Производительность ниже, чем у num2words.
Как вывести число как денежную сумму прописью с указанием валюты?
Библиотека num2words поддерживает режим currency. Пример:
from num2words import num2words
print(num2words(1234.56, lang='ru', to='currency', currency='RUB'))Python число вывести текстом (вывод числа прописью в python)
одна тысяча двести тридцать четыре рубля пятьдесят шесть копеек
Для сумм с копейками дробная часть обрабатывается автоматически. Если нужно вывести только целую часть, используйте to='currency' с округлением.
Для других валют измените параметр currency: 'USD', 'EUR', 'KZT' и т.д. Поддержка валют зависит от версии библиотеки.
Возможные сложности
- Не все валюты имеют корректные формы множественного числа (например, 'долларов' vs 'доллара'). Проверьте перед использованием.
- Суммы с нулевой копеечной частью могут отображаться как 'ноль копеек'.
Расширенные примеры преобразования чисел в текст
1. Использование num2words с разными настройками
Порядковые числительные:
from num2words import num2words
print(num2words(21, lang='ru', ordinal=True))двадцать первый
Число с дробной частью (не денежный режим):
print(num2words(3.14, lang='ru'))три целых четырнадцать сотых
Большое число:
print(num2words(10**15, lang='ru'))один квадриллион
2. Ручная функция с учётом падежа (только для тысяч в родительном)
def число_в_родительном(число):
from num2words import num2words
import pymorphy2
morph = pymorphy2.MorphAnalyzer()
text = num2words(число, lang='ru')
words = []
for word in text.split():
parsed = morph.parse(word)[0]
# Если слово может быть числительным, склоняем в родительный
if 'NUMR' in parsed.tag:
inf = parsed.inflect({'gent'})
words.append(inf.word if inf else word)
else:
words.append(word)
return ' '.join(words)
print(число_в_родительном(567))пятисот шестидесяти семи
Примечание: функция простая и может дать неверный результат для составных числительных (21 -> 'двадцати одного'? на самом деле 'двадцати одного'). В реальных проектах лучше использовать готовые решения.
3. Преобразование числа с ведущими нулями (строковый аргумент)
Если число передано как строка с ведущими нулями, например '00123', нужно сначала преобразовать в int, чтобы удалить нули:
from num2words import num2words
s = '00123'
число = int(s)
print(num2words(число, lang='ru'))сто двадцать три
4. Отрицательные числа и ноль
print(num2words(-10, lang='ru'))
print(num2words(0, lang='ru'))минус десять ноль
5. Денежный формат с разными валютами
print(num2words(999.99, lang='ru', to='currency', currency='USD'))
print(num2words(1000, lang='ru', to='currency', currency='EUR', cents=False))девятьсот девяносто девять долларов девяносто девять центов одна тысяча евро
Параметр cents=False отключает вывод копеек/центов.
6. Сравнение производительности разных методов (для 10 000 итераций)
import timeit
# num2words
setup = 'from num2words import num2words
test = 123456789'
time1 = timeit.timeit('num2words(test, lang="ru")', setup=setup, number=10000)
# pymorphy2 + num2words (только склонение)
setup2 = '''from num2words import num2words
import pymorphy2
morph = pymorphy2.MorphAnalyzer()
test = 123456789
'''
time2 = timeit.timeit('''
text = num2words(test, lang="ru")
' '.join(morph.parse(w)[0].inflect({"gent"}).word for w in text.split())
''', setup=setup2, number=10000)
print(f'num2words: {time1:.3f}s')
print(f'num2words + pymorphy2: {time2:.3f}s')num2words: 1.245s num2words + pymorphy2: 12.876s
Видно, что pymorphy2 добавляет значительную задержку, поэтому его стоит использовать только когда требуется именно изменение падежа.