Module:RuGrammar

-- This module is intended to form plural from Russian nouns, ajectives and simple phrases. It's designed to replace ru:Template:Множ and its subpages, ru:Template:Локатив etc. For declesion, consider please extending grammar: parser function in PHP engine code

local o={};

local cons='бвгджзйклмнпрстфхцчшщ'; -- all consonants local cons7='кгхчжшщ'; -- consonants requiring -и local adjends={['ой']='ые',['ый']='ые',['ий']='ие',['ое']='ые',['ая']='ые',['яя']='ие',['ое']='ые',['ее']='ие'}; local specpl={ ["человек"]="люди", ['мать']='матери', ['дочь']='дочери', ['брат']='братья', ['сын']='сыновья', ['дерево']='деревья', ['чудо']='чудеса', ['ребёнок']='дети', ['дитя']='дети', ['край'] = 'края', ['перо']='перья', ['знамя']='знамёна', ['грузин']='грузины', ['татарин']='татары', ['болгарин']='болгары', ['боярин']='бояре', ['цыган']='цыгане', ['друг']='друзья', ['веко']='веки', ['день']='дни', ['век']='века', ['директор']='директора', ['доктор']='доктора', ['инспектор']='инспектора', ['город']='города', ['вес']='веса', ['поезд']='поезда', ['звезда']='звёзды', ['список']='списки', ['церковь']='церкви' }; -- table of some common special plural cases

function o.pl(p) -- plural formator, second argument mb 0 (undeclesed), 1, 2, 3 or 4 (adjective) local word = p.args[1]; if specpl[word] then return specpl[word] end; local d=p.args[2]; if d==nil then d=o.guessdecl(p) end; if d=='0' then return word elseif d=='a' then if mw.ustring.match(word,'['..cons7..']..$') then return mw.ustring.sub(word,1,-3)..'ие' else return mw.ustring.sub(word,1,-3)..adjends[mw.ustring.sub(word,-2)] end elseif d=='1' then if mw.ustring.sub(word,-1)=='я' or mw.ustring.match(word,'['..cons7..']а$') then return mw.ustring.sub(word,1,-2)..'и' else return mw.ustring.sub(word,1,-2)..'ы' end elseif d=='2' then if mw.ustring.match(word,'о$') then return mw.ustring.sub(word,1,-2)..'а' elseif mw.ustring.match(word,'е$') then return mw.ustring.sub(word,1,-2)..'я' elseif mw.ustring.match(word,'[ьй]$') then return mw.ustring.sub(word,1,-2)..'и' elseif mw.ustring.match(word,'онок$') then return mw.ustring.sub(word,1,-5)..'ата' elseif mw.ustring.match(word,'ёнок$') then return mw.ustring.sub(word,1,-5)..'ята' elseif mw.ustring.match(word,'анин$') then return mw.ustring.sub(word,1,-5)..'ане' elseif mw.ustring.match(word,'янин$') then return mw.ustring.sub(word,1,-5)..'яне' elseif mw.ustring.match(word,'ец$') and not mw.ustring.match(word,'['..cons7..']['..cons7..']ец$') then -- !!second re is wrong for etnochoronims with unstressed -ец like ньюйоркцы if mw.ustring.match(word,'лец$') then return mw.ustring.sub(word,1,-3)..'ьцы' elseif mw.ustring.match(word,'[аоуыэяёюие]ец$') then return mw.ustring.sub(word,1,-3)..'ьцы' else return mw.ustring.sub(word,1,-3)..'цы' end elseif mw.ustring.match(word,'['..cons7..']$') then return word..'и' else return word..'ы' end elseif d=='3' then if mw.ustring.match(word,'мя$') then return mw.ustring.sub(word,1,-3)..'ена' else return mw.ustring.sub(word,1,-2)..'и' end else return " Wrong declesion '"..d.."' in RuGrammar::pl " end end

function o.guessdecl(p) -- guesses declesion type, yet not the best reliable way local word=p.args[1]; if mw.ustring.match(word,'['..cons..'][оыи]й$') or mw.ustring.match(word,'['..cons..'][ая]я$') or mw.ustring.match(word,'['..cons..'][ое]е$') then return 'a' --sometimes wrong elseif mw.ustring.match(word,'['..cons..'][оеь]?$') then return '2' --but mb 3, can't guess w/o dict elseif mw.ustring.match(word,'['..cons..'][ая]$') then if mw.ustring.match(word,'[^'..cons..']мя$') then return '3' else return '1' end else return '0' end end

function o.locative(p) -- consider rewritting grammar: instead of using it! local word=p.args[1]; local locend={['а']='е', ['я']='е', ['й']='е', ['ы']="ах", ['ь']='и'}; -- the last is disputed, most Russian cities on -ь are 3 declesion but some foreign a 2 and thus -е local ec=mw.ustring.sub(word,-1); if mw.ustring.match(word,'ия$') then return mw.ustring.sub(word,1,-2)..'и' elseif mw.ustring.match(word,'['..cons..']ль$') or mw.ustring.sub(word,-4)=='поль' then return mw.ustring.sub(word,1,-2)..'е' elseif locend[ec] then return mw.ustring.sub(word,1,-2)..locend[ec] elseif ec=='я' then return mw.ustring.sub(word,1,-2)..'е' elseif mw.ustring.match(ec,'['..cons..']') then return word..'е' elseif ec=='о' then if mw.ustring.match(word,'[оеё]во$') then return mw.ustring.sub(word,1,-2)..'е' else return word end else return word end end;

return o;