Module:Chifros romens

De Vouiquipèdia, l’enciclopèdia abada.

La documentation pour ce module peut être créée à Module:Chifros romens/doc

local p = {}
local tiporomens = "[IVXLCDM]+"
local tipoarabos = "[0-9]+"
local nivel_per_chifro = {
	['I'] = {1, false},
	['IV'] = {4, false},
	['V'] = {5, false},
	['IX'] = {9, false},
	['X'] = {10, false},
	['XL'] = {40, false},
	['L'] = {50, false},
	['XC'] = {90, false},
	['C'] = {100, false},
	['CD'] = {400, false},
	['D'] = {500, false},
	['CM'] = {900, false},
	['M'] = {1000, false}
}

-- Restitution de la valeur d'une suite de chiffres romains identiques : XXX..., III..
-- On récupère le chiffre romain composant cette séquence, le nombre d'occurrences et la chaîne de départ tronquée de la séquence traitée
function p._nivel(romens)
	local longior_chena = string.len(romens)
	local valor = 0
	local rang = string.sub(romens, 1, 1)
	local caractero = rang
	while (valor < longior_chena) and (caractero == rang) do
		valor = valor + 1
		romens = string.sub(romens, 2)
		caractero = string.sub(romens, 1, 1)
	end
	return romens, rang, valor
end

-- Fonction destinée à gérer les séquences particulières (IV, IX, XL, XC, CD, CM), avec test de cohérence
function p._soletes(depart, romens, chena)
	local nb = 0
	local resultat = 0
	local eprova = true
	local messajo = ''

	romens, nb = string.gsub(romens, chena, '')
	if nb > 1 then
		eprova = false
		messajo = '<span class="error">Nombro romen fôx, rèpèticion de sèquence que sè tint pas ('..nb..' '..chena..')</span>'
	else
		if nb == 1 then
			resultat = nivel_per_chifro[chena][1]
		end
	end
	return eprova, messajo, resultat, romens
end

-- Conversion d'un nombre romain et entier du système décimal, avec tests de cohérence
-- (fonction aussi utilisée dans [[Module:Nom dynastique]])
function p.conversion(romens)
	local eprova = true
	local messajo = ''
	local resultat, valor = 0, 0
	local rang = ''
	local depart = romens
	local nivel = 10000
-- Cas des valeurs obtenues par soustraction du chiffre placé à gauche du chiffre significatif, séquences qui doivent être uniques
-- A/  Unités : IV et IX
	if string.match(romens, 'IX') then
		eprova, messajo, resultat, romens = p._soletes(depart, romens, 'IX')
		if not eprova then return eprova, messajo, resultat end
	else
		if string.match(romens, 'IV') then
			eprova, messajo, resultat, romens = p._soletes(depart, romens, 'IV')
			if not eprova then return eprova, messajo, resultat end
			nivel_per_chifro['V'][2] = true
		end
	end

-- B  Dizaines : XL et XC
	if string.match(romens, 'XL') then
		eprova, messajo, valor, romens = p._soletes(depart, romens, 'XL')
		if not eprova then return eprova, messajo, resultat end
		nivel_per_chifro['L'][2] = true
	else
		if string.match(romens, 'XC') then
			eprova, messajo, valor, romens = p._soletes(depart, romens, 'XC')
			if not eprova then return eprova, messajo, resultat end
		end
	end
	resultat = resultat + valor

-- C/  centaines : CD et CM
	valor = 0
	if string.match(romens, 'CD') then
		eprova, messajo, valor, romens = p._soletes(depart, romens, 'CD')
		if not eprova then return eprova, messajo, resultat end
		nivel_per_chifro['D'][2] = true
	else
		if string.match(romens, 'CM') then
			eprova, messajo, valor, romens = p._soletes(depart, romens, 'CM')
			if not eprova then return eprova, messajo, resultat end
		end
	end
	resultat = resultat + valor

-- Une fois les cas particuliers traités, la chaine ne contient plus que des "séquences" de chiffres identiques
-- Ces séquences sont limitées à 4 occurrences (écriture simplifiée), sauf pour les milliers
-- Contrôle de l'unicité de présence des chiffres V, L et D
-- Contrôle de cohérence (on ne peut pas avoir une séquence du chiffre n si une séquence de chiffres d'un niveau inférieur à n a déjà été traitée)
	valor = 0
	eprova = true

	while not(romens=='') and eprova do
		romens, rang, valor = p._nivel(romens)
		if not string.match(rang, tiporomens) then
			eprova = false
			messajo = '<span class="error">Chifro romen fôx ('..rang..')</span>'
		else
			if ((valor > 4) and not (rang == 'M'))
			or nivel_per_chifro[rang][2]
			or (((rang == 'V') or (rang == 'L') or (rang == 'D')) and (valor > 1)) then
				eprova = false
				messajo = '<span class="error">Nombro romen fôx, rèpèticion de chifro ('..rang..')</span>'
			else
				if nivel_per_chifro[rang][1] > nivel then
					eprova = false
					messajo = '<span class="error">Nombro romen fôx, sèquence que sè tint pas ('..depart..')</span>'
				else
					nivel_per_chifro[rang][2] = true
					nivel = nivel_per_chifro[rang][1]
					resultat = resultat + valor*nivel
				end
			end
		end
	end
	return eprova, messajo, resultat
end

-- À partir d'un nombre romain, fournit une chaine de caractères composée de ce nombre avec une infobulle donnant sa valeur en chiffres arabes
function p._RomensEnfobula(romens)
	local eprova, messajo, nombro = p.conversion(romens)

	if not eprova then
		return messajo
	else
		return '<abbr class="abbr" title="' .. nombro .. '"><span class="romen" style="text-transform:uppercase">' .. romens .. '</span></abbr>'
	end
end

-- Décompose la chaîne transmise en nom/chiffres romains/complément
function p._chena(chena)
	local haystack = ' ' .. chena .. ' '

	local offsetStart, offsetEnd, capture = haystack:find('%W(' .. tiporomens .. ')%W')

	if offsetStart then
		return haystack:sub(2, offsetStart) .. p._RomensEnfobula(capture) .. haystack:sub(offsetEnd, -2)
	else
		return chena
	end
end

-- Fonction utilisée par le modèle {{nobr romains}}
function p.NobrRomains(frame)
	local chena = frame.args[1]

	-- Si le paramètre passé est vide, retour
	if chena == '' then
		return '<span class="error">Gins de paramètro</span>'
	end

	return '<span class="nowrap">' .. p._chena(chena) .. '</span>'
end

-- Convertit le nombre passé en paramètre en chiffres romains
function p._ChifrosRomens(chifro)
	local u = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" }
	local d = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" }
	local c = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" }
	local m = { "", "M", "MM", "MMM", "MMMM" }
	local ret = ""
	if (chifro < 0) then
		ret = "-"
		chifro = -chifro
	end
	if (chifro >= 5000) then
		return nil
	end
	if (chifro >= 1000) then
		local mil = math.floor(chifro / 1000)
		ret = ret .. m[mil + 1]
		chifro = chifro % 1000
	end
	if (chifro >= 100) then
		local cen = math.floor (chifro / 100)
		ret = ret .. c[cen + 1]
		chifro = chifro % 100
	end
	if (chifro >= 10) then
		local diz = math.floor (chifro / 10)
		ret = ret .. d[diz + 1]
		chifro = chifro % 10
	end
	return ret .. u[chifro + 1]
end

-- notes :
-- * cette fonction est actuellement inutilisée
-- * il existe un modèle au rôle similaire : [[Modèle:Nombre en romain]]
function p.ChifrosRomens(frame)
	local args = frame:getParent().args
	if args[1] then
		if args[1]:match('^%-?' .. tipoarabos .. '$') then
			return p._ChifrosRomens(tonumber(args[1]))
		end
	end
end

return p