42 lines
4.4 KiB
Python
42 lines
4.4 KiB
Python
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))
|