Модуль:по-слогам eo

Материал из Викисловаря
Документация

Юнит-тест для модуля (на момент написания не работал по причине отсутствия модуля UnitTest): Обсуждение модуля:по-слогам eo/testcases

local mvorto = {};

--[[
Возвращает слог под указанным номером, либо пустую строку, если такого слога нет

Использование:
{{#invoke:по-слогам eo|getSilabo|слово|номер_слога}}
или
{{#invoke:по-слогам eo|getSilabo|vorto=слово|silabnumero=номер_слога}}

Параметры:
    vorto: строка, в которой необходимо найти указанный слог
    silabnumero: номер слога, который необходимо вернуть. Если не указано, то
    будет возвращён первый слог
]]
function mvorto.getSilabo(frame)
    local new_args = mvorto._getParameters( frame.args, {'vorto', 'silabnumero'} )
    local vorto = new_args['vorto'] or ''
    local silabnumero = tonumber(new_args['silabnumero']) or 1
    
    local silaboj = mvorto.getSilaboj(vorto, false)
    if type(silaboj[silabnumero]) ~= nil then
        return silaboj[silabnumero]
    else
        return ''
    end
end

--[[
Возвращает таблицу (массив) слогов указанного слова

Параметры:
    s: слово, для разбора на слоги
    onlysilaboj: вернуть только массив слогов (без ударений, дефисов и точек)
]]
function mvorto.getSilaboj(s, onlysilaboj)
    local vortlongo = string.len(s)
    local slogi = {}
    
    if s ~= nil and s ~= '' then
        if string.find( s, '-' ) == nil then
            slogi = mvorto._getSl(s)
        else
            --Если есть дефис, резать по дефису и добавлять его как слог
            for v in string.gmatch(s, "([^\\-]+)") do
                if slogi == nil or #slogi == 0 then
                    slogi = mvorto._getSl(v)
                else
                	if onlysilaboj ~= true then table.insert(slogi, '-') end
                    slogi = mvorto.mergeTables(slogi, mvorto._getSl(v))
                end
            end
        end
        
        if onlysilaboj ~= true then
	        finlitero = string.sub(s, vortlongo, vortlongo )
	        if #slogi < 2 then
	            slogi[#slogi] = mvorto.makeStress( slogi[#slogi] )
	        else
	        	if finlitero == "'" then
	                slogi[#slogi] = mvorto.makeStress( slogi[#slogi] )
	            else
	            	if slogi[#slogi-1] == '-' then
	                    slogi[#slogi-2] = mvorto.makeStress( slogi[#slogi-2] )
	                else
	                    slogi[#slogi-1] = mvorto.makeStress( slogi[#slogi-1] )
	                end
	            end
	            
	            if string.len(slogi[#slogi]) == 1 and slogi[#slogi-1] ~= '-' then
	                table.insert(slogi, #slogi, '.')
	            end
	            
	            if string.len(slogi[1]) == 1 and slogi[2] ~= '-' then
	                table.insert(slogi, 2, '.')
	            end
	        end
        end
    else
        return {''}
    end
    
    return slogi
end

--[[
Заменяет все гласные на гласные под ударением

Параметры:
    s: строка, для обработки
]]
function mvorto.makeStress(s)
    s = string.gsub(s, "a", "á")
    s = string.gsub(s, "A", "Á")

    s = string.gsub(s, "o", "ó")
    s = string.gsub(s, "O", "Ó")

    s = string.gsub(s, "e", "é")
    s = string.gsub(s, "E", "É")

    s = string.gsub(s, "i", "í")
    s = string.gsub(s, "I", "Í")

    s = string.gsub(s, "u", "ú")
    s = string.gsub(s, "U", "Ú")
    
    return s;
end

function mvorto._getSl(s)
    local vectors = mw.loadData("Module:по-слогам eo/kombinations")
    
    local result = ""
    
    local slogi = {}
    local vesbukv = mw.loadData("Module:по-слогам eo/masses")
    local notes = ""
    
    --Так как некоторые спецефичные для алфавита эсперанто буквы (ĉ, ĝ, ŭ и др),
    --а так же их заменяющие сочетания букв (cx, sx, ux и тд) занимают
    --по 2 символа, то работаем не с набором символов, а с набором их сочетаний
    local literoj = {}
    local vortdlin = string.len(s)
    local v = ''
    local preterlasu = false
    for i = 1,vortdlin do
        if preterlasu then
            preterlasu = false
        else
            if i+1 <= vortdlin then
                v = string.lower(string.sub(s, i, i+1))
            else
                v = string.sub(s, i, i)
            end
            
            if v == 'ĉ' or v == 'ĝ' or v == 'ĥ' or v == 'ĵ' or v == 'ŝ' or
            v == 'ŭ' or v == 'cx' or v == 'gx' or v == 'hx' or v == 'jx' or
            v == 'sx' or v == 'ux' then
                --так как проверка была по строчным быквам, берём сноваоригинал
                v = string.sub(s, i, i+1)
                preterlasu = true
            else
                v = string.sub(s, i, i)
                if type(vesbukv[v]) == nil then
                    v = 'a'
                end
            end
            
            table.insert(literoj, v)
        end
    end
    
    for i,v in pairs(literoj) do
        v = string.lower(v)
        if v == 'ĉ' then
            v = 'cx'
        elseif v == 'ĝ' then
            v = 'gx'
        elseif v == 'ĥ' then
            v = 'hx'
        elseif v == 'ĵ' then
            v = 'jx'
        elseif v == 'ŝ' then
            v = 'sx'
        elseif v == 'ŭ' then
            v = 'ux'
        end

        v = vesbukv[v]
        if v == nil then
            v = 1
        end
        notes = notes .. v
    end
    
    local prefx = '';
    local postfx = '';
    v = '';
    
    local ia = 0;
    local ib;
    for i = 1,#literoj do
        v = string.sub(notes, i, i);
        if v == "3" then
            if prefx == '' and #slogi == 0 then
                ia = i
                prefx = table.concat(literoj, '', 1, ia)
            else
                local vect
                ib = i
                local kombin = string.sub(notes, ia+1, ib-1)
                if string.len(kombin) == 0 then
                    vect = 0
                else
                    vect = vectors[kombin]
                    
                    -- Если дифтонг, то сдвигаем вектор разреза слога
                    if vect == 0
                    and ( literoj[ia+1] == "ux"
                    or literoj[ia+1] == "j" ) then
                    	vect = 1
                	end
                end
                
                if vect > 0 then
                    postfx = table.concat(literoj, '', ia+1, ia+vect)
                else
                    postfx = ''
                end
                
                local newslog = prefx .. postfx
                table.insert(slogi, newslog)
                prefx = table.concat(literoj, '', ia+vect+1, ib)
                ia = ib
                ib = nil
            end
        end
    end
    if ia ~= vortdlin then
        local newslog = prefx .. table.concat(literoj, '', ia+1, #literoj)
        table.insert(slogi, newslog)
    else
        table.insert(slogi, prefx)
    end

    return slogi;
end

function mvorto.mergeTables( t1, t2 )
    for k,s in pairs( t2 ) do table.insert( t1, s ) end
    return t1;
end

function mvorto._getParameters( frame_args, arg_list )
    local new_args = {};
    local index = 1;
    local value;
 
    for i,arg in ipairs( arg_list ) do
        value = frame_args[arg]
        if value == nil then
            value = frame_args[index];
            index = index + 1;
        end
        new_args[arg] = value;
    end
 
    return new_args;
end  
 
return mvorto