Modul:Rediger tabel

Documentation icon Moduldokumentation[opret]
-- et modul til at ændre indholdet eller udseendet af en tabel i en wikiartikel
-- der findes i øjeblikket fire tilgængelige funktioner: 
-- procentkolonne, sletkolonne, sortertabel, ombytkolonner

local p = {}

local function inlist (name, list)
	for n in mw.text.gsplit(list, '%s*,%s*') do
		if n == name then return true end
	end
	return false
end

local function konstruer_tabel (args)
	local tabel = ''
    local start = true
    for key, arg in pairs(args) do
      if tonumber(key) then
    	if not start then 
    		tabel = tabel..'|'..arg 
    	else 
    		tabel = arg
    		start = false
    	end
      end
    end
	tabel = mw.text.trim(tabel)
	return tabel
end

local function opdel_tabel_i_raekker (tabel)
    local rowtabel = {}
    local k, i = 1, 1
    local row, rowtotal

    -- find første række:
    k = string.find(tabel,"^|%-%s*\n|.-\n|%-")
    if k then
    	row = string.match(tabel,"^|%-%s*\n(|.-)\n|%-")
    	rowtabel[1] = row
        i = 2
        k = k + 3 
    else 
    	error("Inputtet skal starte med: |-", 0)
    end

    -- find de næste rækker:
    repeat row = string.match(tabel,"\n|%-%s*\n(|.-)\n|%-", k) 
    	if row then
    		rowtabel[i] = row
       		i = i+1
       		k = string.find(tabel,"\n|%-%s*\n|.-\n|%-",k) + 3
       	end
    until not row
    
	local rk = i - 1 -- antal rækker
    -- find sidste række:
    row = string.match(tabel,"\n|%-%s*\n(|.-)$", k )
    if row then 
    	rowtabel[i] = row 
    	rk = i
    end
    return rowtabel, rk
end

function celler_i_tabel(rowtabel)
    local i,j,k,l,c,m = 0,0,0,0,0,0
    celletabel = {}
    local celle
    -- find indholdet af cellerne
    for key, row in pairs(rowtabel) do
    	celletabel[key] = {}
    	k = 1  -- position 1
    	c = 1  -- celle 1
    	repeat 
    		i = string.find(row,'|[^\n]-||',k)
    		if i ~= k then 
    			j = string.find(row,'|.-\n',k) 
    		end
    		if i ~= k and j ~= k then 
    			m = string.find(row,'|.-$',k) 
    		end
    		if i==k then
    			celle = string.match(row,'|([^\n]-)||',k)
    			l = k + string.len(celle) + 2
    			if string.match(celle,'|') then
    				local attribut = string.match(celle,'(.-)|')
    				local indhold = string.match(celle,'|(.+)')
    				table.insert(celletabel[key], { ['attribut'] = attribut, ['indhold'] = indhold } )
    			else
    				local indhold = celle
    				table.insert(celletabel[key], { ['indhold'] = indhold } )
    			end
	    	elseif j==k then -- sidste celle på linjen med linjeskift
	  	    	celle = string.match(row,'|(.-)\n',k)
	  	    	l = k + string.len(celle) + 2
    			if string.match(celle,'|') then
    				local attribut = string.match(celle,'(.-)|')
    				local indhold = string.match(celle,'|(.+)')
    				local ctabel = { ['attribut'] = attribut, ['indhold'] = indhold, ['lskift'] = true }
    				table.insert(celletabel[key], ctabel )
    			else
    				local indhold = celle
    				table.insert(celletabel[key], { ['indhold'] = indhold, ['lskift'] = true } )
    			end
    		elseif m==k then -- sidste celle på linjen og i rækken
	  	    	celle = string.match(row,'|(.-)$',k)
	  	    	l = k + string.len(celle) + 2
    			if string.match(celle,'|') then
    				local attribut = string.match(celle,'(.-)|')
    				local indhold = string.match(celle,'|(.+)')
    				table.insert(celletabel[key], { ['attribut'] = attribut, ['indhold'] = indhold } )
    			else
    				local indhold = celle
    				table.insert(celletabel[key], { ['indhold'] = indhold } )
    			end
    		else
    			error('Der er noget galt nær række '..key, 0)
	    	end
	    	c = c + 1
	    	k = l
		until l>string.len(row) or ((not i) and (not j) and (not m))
    end
    local kol = c - 1   -- antal kolonner
    return celletabel, kol
end
    
local function laes_tabel (args)
    local tabel = konstruer_tabel(args)
    local rowtabel, rk = opdel_tabel_i_raekker(tabel)
    
    rk = tonumber(args["antal talrækker"]) or tonumber(rk)
    if not rk then
    	error('Skabelonen kan ikke fastslå antallet af rækker', 0)
    end
    
    local celletabel, kol = celler_i_tabel(rowtabel)
    kol = tonumber(args["totalt antal kolonner"]) or tonumber(kol)
    if not kol then
    	error('Skabelonen kan ikke fastslå antallet af kolonner', 0)
    end
    return celletabel, rk, kol
end

function p.procentkolonne (frame)
    p.frame = frame
    
	local args
    if frame == mw.getCurrentFrame() then
		args = frame:getParent().args
	else
		args = frame.args
	end	
    
	local frakol = tonumber(args.frakolonne)
	local tilkol = tonumber(args.tilkolonne)
	local procentkol = tonumber(args.procentkolonne) 
	if not (procentkol and tilkol and frakol) then
		error("Der mangler en eller flere af parametrene: ''frakolonne'', ''tilkolonne'', ''procentkolonne''", 0)
	end

    local celletabel, rk, kol = laes_tabel(args)

	local tester = args.test or ''
	local decimaler = mw.text.trim(args.decimaler or '0')
	decimaler = tostring(math.floor(tonumber(decimaler) or 0))
	local tilkoltal, frakoltal
	
    local wikitext = ''
    for row = 1, rk do
    	for col = 1, kol do
   			if col == 1 then wikitext = wikitext..'|-\n|'
   			else 
   				if celletabel[row][col-1] and celletabel[row][col-1].lskift then 
   					wikitext = wikitext .. '|'
   				else
   					wikitext = wikitext .. '||'
   				end
   			end
   			if celletabel[row][col] and celletabel[row][col].attribut then 
   				wikitext = wikitext .. celletabel[row][col].attribut .. '|'
   			end
   			if celletabel[row][col] and celletabel[row][col].indhold then 
   				if tester~='ja' and procentkol and frakol and tilkol and col==procentkol then
   				    tilkoltal = celletabel[row][tilkol].indhold
   				    frakoltal = celletabel[row][frakol].indhold
   				    tilkoltal = string.gsub(tilkoltal, '%.', '')
   				    frakoltal = string.gsub(frakoltal, '%.', '')
   					local tal = 100 * (tilkoltal - frakoltal) / frakoltal
   					tal = string.format('%.'..decimaler..'f', tal)
   					if tonumber(tal) > 0 then tal = '+'..tal end
   					tal = string.gsub(tal, '%.', ',')
   					wikitext = wikitext .. ' ' .. tal .. '% '
	        	else
	    	    	wikitext = wikitext .. celletabel[row][col].indhold
	    		end
   			end
   			if celletabel[row][col] and celletabel[row][col].lskift then 
   				wikitext = wikitext .. '\n'
   			end
   			if col==kol and row<rk then wikitext=wikitext..'\n' end
    	end
    end
    return wikitext
end

function p.sletkolonne (frame)
    p.frame = frame
    
	local args
    if frame == mw.getCurrentFrame() then
		args = frame:getParent().args
	else
		args = frame.args
	end	
    
    local celletabel, rk, kol = laes_tabel(args)

	local sletkolonne = args.sletkolonne 
	local tester = args.test or ''
	
    local wikitext = ''
    for row = 1, rk do
    	for col = 1, kol do
    		if not sletkolonne or not inlist(tostring(col), sletkolonne ) then 
    			if col == 1 then wikitext = wikitext..'|-\n|'
    			else 
    				if celletabel[row][col-1] and celletabel[row][col-1].lskift then 
    					wikitext = wikitext .. '|'
    				else
    					wikitext = wikitext .. '||'
    				end
    			end
    			if celletabel[row][col] and celletabel[row][col].attribut then 
    				wikitext = wikitext .. celletabel[row][col].attribut .. '|'
    			end
    			if celletabel[row][col] and celletabel[row][col].indhold then 
	    	    	wikitext = wikitext .. celletabel[row][col].indhold
    			end
    			if celletabel[row][col] and celletabel[row][col].lskift then 
    				wikitext = wikitext .. '\n'
    			end
    			if col==kol and row<rk then wikitext=wikitext..'\n' end
    		end
    	end
    end
    return wikitext
end

function p.sortertabel (frame)
    p.frame = frame
    
	local args
    if frame == mw.getCurrentFrame() then
		args = frame:getParent().args
	else
		args = frame.args
	end	
    
    local celletabel, rk, kol = laes_tabel(args)

	local nrkolonne = tonumber(args.nrkolonne)
	local kolonne = tonumber(args.sorterkolonne)
	if not kolonne then error('Parameter "sorterkolonne" mangler eller er ikke et tal', 0) end
	local alfabetisk = args.alfabetisk or ''
	local stigende = args.stigende or ''
	local tester = args.test or ''
	args = nil -- bruger mindre memory

	table.sort(celletabel, function (a,b)
		local x = a[kolonne].indhold
		local y = b[kolonne].indhold
		if alfabetisk ~= 'ja' then 
			x = string.gsub(x, '%%', '') -- fjern procenttegn
			x = string.gsub(x, '%.', '') -- fjern tusindadskiller
			x = string.gsub(x, ',', '.') -- erstat decimalkomma med punktum
			x = tonumber(x) 
			y = string.gsub(y, '%%', '')
			y = string.gsub(y, '%.', '')
			y = string.gsub(y, ',', '.')
			y = tonumber(y)
		end
		if not x or not y then error('Det lykkedes ikke skabelonen at læse kolonne '..kolonne..' som tal. Sæt evt. parameter alfabetisk=ja', 0) end
		if stigende == 'ja' then
			return x < y
		else
			return x > y
		end
	end) 
	local gentag = 0
    local linjetabel = {}
    
    for row = 1, rk do
    	for col = 1, kol do
   			if col == 1 then 
   				linjetabel[row] = '|-\n|'
   			else 
   				if celletabel[row][col-1] and celletabel[row][col-1].lskift then 
  					linjetabel[row] = linjetabel[row] .. '|'
  				else
   					linjetabel[row] = linjetabel[row] .. '||'
   				end
   			end
   			if celletabel[row][col] and celletabel[row][col].attribut then 
   				linjetabel[row] = linjetabel[row] .. tostring(celletabel[row][col].attribut) .. '|'
   			end
   			if celletabel[row][col] and celletabel[row][col].indhold then 
   				if nrkolonne and nrkolonne == col then
   					if row > 1 and celletabel[row][kolonne].indhold == celletabel[row-1][kolonne].indhold then
   						if gentag == 0 then gentag = row - 1 end
   						linjetabel[row] = linjetabel[row]..' '..tostring(gentag)..' ' -- samme rangering som forrige række
   					else
   						linjetabel[row] = linjetabel[row] .. ' ' .. tostring(row) .. ' '
   						gentag = 0
   					end
   				else
   					linjetabel[row] = linjetabel[row] .. tostring(celletabel[row][col].indhold)
   				end
   			end
   			if celletabel[row][col] and celletabel[row][col].lskift then 
   				linjetabel[row] = linjetabel[row] .. '\n'
   			end
    	end
    end
    
    return table.concat(linjetabel,'\n')
end

function p.ombytkolonner (frame)
    p.frame = frame
    
	local args
    if frame == mw.getCurrentFrame() then
		args = frame:getParent().args
	else
		args = frame.args
	end	
    
    local celletabel, rk, kol = laes_tabel(args)

	local kolonneA = tonumber(args.kolonneA)
	if not kolonneA then error('Parameter "kolonneA" mangler eller er ikke et tal', 0) end
	local kolonneB = tonumber(args.kolonneB)
	if not kolonneB then error('Parameter "kolonneB" mangler eller er ikke et tal', 0) end
	local tester = args.test or ''
	
    local wikitext = ''
    for row = 1, rk do
    	for col = 1, kol do
   			if col == 1 then wikitext = wikitext..'|-\n|'
   			else 
   				if celletabel[row][col-1] and celletabel[row][col-1].lskift then 
   					wikitext = wikitext .. '|'
   				else
   					wikitext = wikitext .. '||'
   				end
   			end
   			if col ~= kolonneA and col ~= kolonneB then
	   			if celletabel[row][col] and celletabel[row][col].attribut then 
   					wikitext = wikitext .. celletabel[row][col].attribut .. '|'
   				end
   				if celletabel[row][col] and celletabel[row][col].indhold then 
    	    		wikitext = wikitext .. celletabel[row][col].indhold
   				end
   			elseif col == kolonneA then
	   			if celletabel[row][kolonneB] and celletabel[row][kolonneB].attribut then 
   					wikitext = wikitext .. celletabel[row][kolonneB].attribut .. '|'
   				end
   				if celletabel[row][kolonneB] and celletabel[row][kolonneB].indhold then 
    	    		wikitext = wikitext .. celletabel[row][kolonneB].indhold
   				end
   			else -- col = kolonneB
   				if celletabel[row][kolonneA] and celletabel[row][kolonneA].attribut then 
   					wikitext = wikitext .. celletabel[row][kolonneA].attribut .. '|'
   				end
   				if celletabel[row][kolonneA] and celletabel[row][kolonneA].indhold then 
    	    		wikitext = wikitext .. celletabel[row][kolonneA].indhold
   				end
			end
   			if celletabel[row][col] and celletabel[row][col].lskift then 
   				wikitext = wikitext .. '\n'
   			end
   			if col==kol and row<rk then wikitext=wikitext..'\n' end
    	end
    end
    return wikitext
end


return p