Склонение слов в зависимости от числа
Есть функция которая выводит стаж.
Можно ли добавить в функцию склонить слов в зависимости от числа которое выводится?
Подставить вместо:
11111 - год, года, лет
22222 - месяц, месяцев
33333 - день, дня, дней
def stag(message):
conn = sqlite3.connect(settings.DATABASE)
cursor = conn.cursor()
sql = """select last_name, first_name, third_name, data_p, data_z,
alldays / 365 as years,
alldays % 365 / 31 as month,
alldays % 30 as days
from (select last_name, first_name, third_name, data_p, data_z,
CAst((julianday(ifnull(data_z, 'now')) - julianday(data_p)) as Integer) as alldays
from dovidnyk) WHERE last_name = ?"""
cursor.execute(sql,)
result = cursor.fetchall()
for fn in result:
msg = "<i>? <u>ФИО</u></i>: <b>{} {} {}</b>\n" \
"<i>? <u>Дата приема</u></i>: <b>{}</b>\n" \
"Стаж {} 11111 {} 22222 {} 33333\n".format(fn[0], fn[1], fn[2], fn[3], fn[4], fn[5])
bot.send_message(message.from_user.id, msg, reply_markup=keyboard, parse_mode='HTML')
Ответы (2 шт):
Автор решения: Ruslan G.
→ Ссылка
Может не самое элегантное решение, но как вариант.
dmy = {'y': 2, 'm': 5, 'd': 10}
words = {'y': ['лет', 'год', 'года'], 'm': ['месяцев', 'месяц', 'месяца'], 'd': ['дней', 'день', 'дня']}
out = []
for k, v in dmy.items():
remainder = v % 10
if v == 0 or remainder == 0 or remainder >= 5 or v in range(11, 19):
st = str(v), words[k][0]
elif remainder == 1:
st = str(v), words[k][1]
else:
st = str(v), words[k][2]
out.append(" ".join(st))
print(" ".join(out))
Вывод:
2 года 5 месяцев 10 дней
UPD: Например, вот так:
import sqlite3
conn = sqlite3.connect('111.db')
cursor = conn.cursor()
# Записи в таблице:
# Иванов Иван Иванович 2001-02-01 2006-08-02
# Смирнов Андрей Анатольевич 2002-03-05 2012-08-12
sql = """select last_name, first_name, third_name, data_p, data_z,
alldays / 365 as years,
alldays % 365 / 31 as month,
alldays % 30 as days
from (select last_name, first_name, third_name, data_p, data_z,
CAST((julianday(ifnull(data_z, 'now')) - julianday(data_p)) as Integer) as alldays
from dovidnyk) """
cursor.execute(sql,)
result = cursor.fetchall()
# [('Иванов', 'Иван', 'Иванович', '2001-02-01', '2006-08-02', 5, 5, 28)]
for fn in result:
dmy = {'y': fn[5], 'm': fn[6], 'd': fn[7]}
words = {'y': ['лет', 'год', 'года'], 'm': ['месяцев', 'месяц', 'месяца'], 'd': ['дней', 'день', 'дня']}
out = []
for k, v in dmy.items():
remainder = v % 10
if v == 0 or remainder == 0 or remainder >= 5 or v in range(11, 19):
st = str(v), words[k][0]
elif remainder == 1:
st = str(v), words[k][1]
else:
st = str(v), words[k][2]
out.append(" ".join(st))
msg = "<i>? <u>ФИО</u></i>: <b>{} {} {}</b>\n" \
"<i>? <u>Дата приема</u></i>: <b>{}</b>\n" \
"Стаж {} {} {} \n".format(fn[0], fn[1], fn[2], fn[3], out[0], out[1], out[2])
print(msg)
conn.close()
Вывод:
<i>? <u>ФИО</u></i>: <b>Иванов Иван Иванович</b>
<i>? <u>Дата приема</u></i>: <b>2001-02-01</b>
Стаж 5 лет 5 месяцев 28 дней
<i>? <u>ФИО</u></i>: <b>Смирнов Андрей Анатольевич</b>
<i>? <u>Дата приема</u></i>: <b>2002-03-05</b>
Стаж 10 лет 5 месяцев 3 дня
UPD2: Можно еще добавить conn.row_factory = sqlite3.Row перед cursor = conn.cursor() тогда результат запроса будет сразу в dict, и код немного упростится.
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute(sql,)
for fn in cursor.fetchall():
fn = dict(fn)
words = {'years': ['лет', 'год', 'года'], 'month': ['месяцев', 'месяц', 'месяца'], 'days': ['дней', 'день', 'дня']}
for k in words.keys():
remainder = fn[k] % 10
if fn[k] == 0 or remainder == 0 or remainder >= 5 or fn[k] in range(11, 19):
st = str(fn[k]), words[k][0]
elif remainder == 1:
st = str(fn[k]), words[k][1]
else:
st = str(fn[k]), words[k][2]
fn[k] = " ".join(st)
msg = "<i>? <u>ФИО</u></i>: <b>{} {} {}</b>\n" \
"<i>? <u>Дата приема</u></i>: <b>{}</b>\n" \
"Стаж {} {} {} \n".format(fn['last_name'],
fn['first_name'], fn['third_name'], fn['data_p'], fn['years'], fn['month'], fn['days'])
print(msg)
conn.close()
Автор решения: Aleksei Trankov
→ Ссылка
age_token = lambda age_to: (
(age_to in range(5, 20)) and 'лет' or
(1 in (age_to, (diglast := age_to % 10))) and 'год' or
({age_to, diglast} & {2, 3, 4}) and 'года' or 'лет')
>>> f'50 {age_token(50)}'
50 лет
То же самое с подстановкой нужного слова
def numeral_noun_declension(
number,
nominative_singular,
genetive_singular,
nominative_plural
):
return (
(number in range(5, 20)) and nominative_plural or
(1 in (number, (diglast := number % 10))) and nominative_singular or
({number, diglast} & {2, 3, 4}) and genetive_singular or nominative_plural
)
>>> 22, numeral_noun_declension(22, 'собака', 'собаки', 'собак')
22, собаки