Module:Chifros romens
La documentation pour ce module peut être créée à Module:Chifros romens/doc
-- luacheck: globals mw, no max line length
local p = {}
local tiporomens = "[IVXLCDM]+"
local tipoarabos = "[0-9]+"
local nivel_per_chifro = {
['I'] = 1,
['IV'] = 4,
['V'] = 5,
['IX'] = 9,
['X'] = 10,
['XL'] = 40,
['L'] = 50,
['XC'] = 90,
['C'] = 100,
['CD'] = 400,
['D'] = 500,
['CM'] = 900,
['M'] = 1000,
}
-- Restitution de la valeur d'une suite de chiffres romains identiques : XXX..., III..
-- On récupère la chaîne de départ tronquée de la séquence traitée, le chiffre romain composant cette séquence et le nombre d'occurrences
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._solets(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]
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 rangs_avengies = {}
for k, _ in pairs(nivel_per_chifro) do
rangs_avengies[k] = false
end
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._solets(romens, 'IX')
if not eprova then return eprova, messajo, resultat end
else
if string.match(romens, 'IV') then
eprova, messajo, resultat, romens = p._solets(romens, 'IV')
if not eprova then return eprova, messajo, resultat end
rangs_avengies['V'] = true
end
end
-- B Dizaines : XL et XC
if string.match(romens, 'XL') then
eprova, messajo, valor, romens = p._solets(romens, 'XL')
if not eprova then return eprova, messajo, resultat end
rangs_avengies['L'] = true
else
if string.match(romens, 'XC') then
eprova, messajo, valor, romens = p._solets(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._solets(romens, 'CD')
if not eprova then return eprova, messajo, resultat end
rangs_avengies['D'] = true
else
if string.match(romens, 'CM') then
eprova, messajo, valor, romens = p._solets(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 romens ~= '' 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>'
break
end
if ((valor > 4) and not (rang == 'M'))
or rangs_avengies[rang]
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>'
break
end
if nivel_per_chifro[rang] > nivel then
eprova = false
messajo = '<span class="error">Nombro romen fôx, sèquence que sè tint pas ('..depart..')</span>'
break
end
rangs_avengies[rang] = true
nivel = nivel_per_chifro[rang]
resultat = resultat + valor*nivel
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, captura = mw.ustring.find(haystack, '%W(' .. tiporomens .. ')%W')
if offsetStart then
return mw.ustring.sub(haystack, 2, offsetStart) .. p._RomensEnfobula(captura) .. mw.ustring.sub(haystack, offsetEnd, -2)
else
return chena
end
end
-- Fonction utilisée par le modèle {{nobr romains}}
function p.NobrRomens(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