Files

42 lines
4.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import re
U=["ноль","один","два","три","четыре","пять","шесть","семь","восемь","девять","десять","одиннадцать","двенадцать","тринадцать","четырнадцать","пятнадцать","шестнадцать","семнадцать","восемнадцать","девятнадцать"]
T=["","","двадцать","тридцать","сорок","пятьдесят","шестьдесят","семьдесят","восемьдесят","девяносто"]
H=["","сто","двести","триста","четыреста","пятьсот","шестьсот","семьсот","восемьсот","девятьсот"]
def card(n):
if n<20: return U[n]
if n<100: return (T[n//10]+(" "+U[n%10] if n%10 else ""))
if n<1000: return (H[n//100]+(" "+card(n%100) if n%100 else ""))
if n<1000000:
th,r=divmod(n,1000); t=th%10; tt=th%100
w=card(th) if th>2 or th>=20 else ""
if th==1: w="одна тысяча"
elif th==2: w="две тысячи"
else:
w=card(th)
w=re.sub(r"один$","одна",w); w=re.sub(r"два$","две",w)
w+=" "+("тысяча" if t==1 and tt!=11 else "тысячи" if 2<=t<=4 and not 12<=tt<=14 else "тысяч")
return w+(" "+card(r) if r else "")
return str(n)
ORD={"ноль":"нулев","один":"перв","два":"втор","три":"трет","четыре":"четвёрт","пять":"пят","шесть":"шест","семь":"седьм","восемь":"восьм","девять":"девят","десять":"десят","одиннадцать":"одиннадцат","двенадцать":"двенадцат","тринадцать":"тринадцат","четырнадцать":"четырнадцат","пятнадцать":"пятнадцат","шестнадцать":"шестнадцат","семнадцать":"семнадцат","восемнадцать":"восемнадцат","девятнадцать":"девятнадцат","двадцать":"двадцат","тридцать":"тридцат","сорок":"сороков","пятьдесят":"пятидесят","шестьдесят":"шестидесят","семьдесят":"семидесят","восемьдесят":"восьмидесят","девяносто":"девяност","сто":"сот","двести":"двухсот","триста":"трёхсот","четыреста":"четырёхсот","пятьсот":"пятисот","шестьсот":"шестисот","семьсот":"семисот","восемьсот":"восьмисот","девятьсот":"девятисот","тысяча":"тысячн","тысячи":"тысячн","тысяч":"тысячн"}
# ending by case/gender: suffix of written form -> ending (hard stem / трет soft)
END={"й":"ый","го":"ого","му":"ому","м":"ом","е":"ое","я":"ая","ю":"ую","х":"ых","ми":"ыми"}
def ordinal(n,suf):
ws=card(n).split(); last=ws[-1]; stem=ORD.get(last,last)
e=END.get(suf,"ый")
if stem=="трет": e={"ый":"ий","ого":"ьего","ому":"ьему","ом":"ьем","ое":"ье","ая":"ья","ую":"ью","ых":"ьих","ыми":"ьими"}[e]
elif stem in("втор","сороков") or stem.endswith(("тысячн",)):
e=e.replace("ый","ой") if stem=="втор" or stem=="сороков" else e
if e=="ый" and stem in("втор","шест","седьм","восьм","сороков"): e="ой"
return " ".join(ws[:-1]+[stem+e])
def normalize(t):
t=t.replace("\xa0"," ").replace("•","").replace("*","").replace("_"," ").replace("–",",").replace("№","номер ")
t=re.sub(r"(\d+)%",lambda m:card(int(m[1]))+" процентов",t)
t=re.sub(r"\b(\d+)-(й|го|му|м|е|я|ю|х|ми)\b",lambda m:ordinal(int(m[1]),m[2]),t)
t=re.sub(r"\b(\d+)\s+(году|года|год|годом)\b",lambda m:ordinal(int(m[1]),{"году":"м","года":"го","год":"й","годом":"м"}[m[2]])+" "+m[2],t)
t=re.sub(r"^\s*(\d+)\.\s",lambda m:card(int(m[1]))+". ",t,flags=re.M)
t=re.sub(r"\d+",lambda m:card(int(m[0])),t)
t=re.sub(r"[ \t]{2,}"," ",t)
return t
if __name__=="__main__":
for s in ["в 508 году","3-й ярус","341-го дня","34% урожая","1200 монет","1. Первое","до 507 года","2-ю неделю","3-е место","21 кролик"]: print(s,"->",normalize(s))