Aller au contenu

Module:Chiffres romains

Cette page fait l’objet d’une mesure de semi-protection étendue.
Une page de Wikipédia, l'encyclopédie libre.
Ceci est une version archivée de cette page, en date du 10 décembre 2017 à 18:13 et modifiée en dernier par Od1n (discuter | contributions) (je le mentionne au cas où, permet aussi d'envoyer vers ce module qui aurait aussi besoin de corrections). Elle peut contenir des erreurs, des inexactitudes ou des contenus vandalisés non présents dans la version actuelle.

 Documentation[voir] [modifier] [historique] [purger]

Ce module est utilisé par (non exhaustif) :

Voir aussi :

local p = {}
local Outils = require( 'Module:Outils' )
local trim = Outils.trim
local typeromains = "[IVXLCDM]+"
local typearabes = "[0-9]+"
local niveau_par_chiffre = {
	['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'occurrence et la chaîne de départ tronquée de la séquence traitée
function p._niveau(romains)
	local longueur_chaine = string.len(romains)
	local valeur = 0
	local rang = string.sub(romains, 1, 1)
	local caractere = rang
	while (valeur < longueur_chaine) and (caractere == rang) do
		valeur = valeur + 1
		romains = string.sub(romains, 2)
		caractere = string.sub(romains, 1, 1)
	end
	return romains, rang, valeur
end

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

	romains, nb = string.gsub(romains, chaine, '')
	if nb > 1 then
		test = false
		message = Outils.erreur('Nombre romain incorrect, répétition de séquence incohérente ('..nb..' '..chaine..')')
	else
		if nb == 1 then
			resultat = niveau_par_chiffre[chaine][1]
		end
	end
	return test, message, resultat, romains
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(romains)
	local test = true
	local message = ''
	local resultat, valeur = 0, 0
	local rang = ''
	local depart = romains
	local niveau = 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(romains, 'IX') then
		test, message, resultat, romains = p._uniques(depart, romains, 'IX')
		if not test then return test, message, resultat end
	else
		if string.match(romains, 'IV') then
			test, message, resultat, romains = p._uniques(depart, romains, 'IV')
			if not test then return test, message, resultat end
			niveau_par_chiffre['V'][2] = true
		end
	end

-- B  Dizaines : XL et XC
	if string.match(romains, 'XL') then
		test, message, valeur, romains = p._uniques(depart, romains, 'XL')
		if not test then return test, message, resultat end
		niveau_par_chiffre['L'][2] = true
	else
		if string.match(romains, 'XC') then
			test, message, valeur, romains = p._uniques(depart, romains, 'XC')
			if not test then return test, message, resultat end
		end
	end
	resultat = resultat + valeur

-- C/  centaines : CD et CM
	valeur = 0
	if string.match(romains, 'CD') then
		test, message, valeur, romains = p._uniques(depart, romains, 'CD')
		if not test then return test, message, resultat end
		niveau_par_chiffre['D'][2] = true
	else
		if string.match(romains, 'CM') then
			test, message, valeur, romains = p._uniques(depart, romains, 'CM')
			if not test then return test, message, resultat end
		end
	end
	resultat = resultat + valeur

-- 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)
	valeur = 0
	test = true

	while not(romains=='') and test do
		romains, rang, valeur = p._niveau(romains)
		if not string.match(rang, typeromains) then
			test = false
			message = Outils.erreur('Chiffre romain incorrect ('..rang..')')
		else
			if ((valeur > 4) and not (rang == 'M'))
			or niveau_par_chiffre[rang][2]
			or (((rang == 'V') or (rang == 'L') or (rang == 'D')) and (valeur > 1)) then
				test = false
				message = Outils.erreur('Nombre romain incorrect, répétiion de chiffre ('..rang..')')
			else
				if niveau_par_chiffre[rang][1] > niveau then
					test = false
					message = Outils.erreur('Nombre romain incorrect, séquence incohérente ('..depart..')')
				else
					niveau_par_chiffre[rang][2] = true
					niveau = niveau_par_chiffre[rang][1]
					resultat = resultat + valeur*niveau
				end
			end
		end
	end
	return test, message, resultat
end

-- A partir d'un nombre romain, fournit une chaine de caractères composée de ce nombre son infobulle donnant sa valeur en chiffres arabes
function p._RomainsInfobulle(romains)
	local test, message, nombre = p.conversion(romains)

	if not test then
		return message
	else
		return '<abbr class="abbr" title="' .. nombre .. '"><span class="romain" style="text-transform:uppercase">' .. romains .. '</span></abbr>'
	end
end

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

	local offsetStart, offsetEnd, capture = haystack:find('%U(' .. typeromains .. ')%U')

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

function p.NobrRomains(frame)
	local chaine = frame.args[1]

	-- Si le paramètre passé est vide, retour
	if #chaine == 0 then
		return Outils.erreur('Aucun paramètre')
	end

	return '<span class="nowrap">' .. p._chaine(chaine) .. '</span>'
end

-- convertit le nombre passé en paramètre en chiffres romains
function p._ChiffresRomains(chiffre)
	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 (chiffre < 0) then
		ret = "-"
		chiffre = -chiffre
	end
	if (chiffre >= 1000) then
		local mil = math.floor(chiffre / 1000)
		ret = ret .. m[mil + 1]
		chiffre = chiffre % 1000
	end
	if (chiffre >= 100) then
		local cen = math.floor (chiffre / 100)
		ret = ret .. c[cen + 1]
		chiffre = chiffre % 100
	end
	if (chiffre >= 10) then
		local diz = math.floor (chiffre / 10)
		ret = ret .. d[diz + 1]
		chiffre = chiffre % 10
	end
	return ret .. u[chiffre + 1]
end

function p.ChiffresRomains(frame)
	local args = frame:getParent().args
	if args[1] then
		if string.match(args[1], typearabes) == args[1] then
			return p._ChiffresRomains(tonumber(args[1]))
		end
	end
end

return p