Module:MathRoman

From Guild of Archivists

Documentation for this module may be created at Module:MathRoman/doc

 --[[ 20120505 19:50 calcul de nombre romain pour http://fr.wikisource.org/
 script en langage LUA, exemples d'appels :
 valeurDeRomain('MCXI')
 testerDesRomains('vue') parametre obsolete
 http://phrogz.net/Lua/LearningLua_FromJS.html   Learning Lua/From JS
 http://www.lua.org/pil/   Programming in Lua reference
 http://www.lua.org/cgi-bin/demo   Demo Try Lua
 20120503 22:16 tests partiel OK
 20120504 22:57 tests complets. Your program ran successfully.
 20120505 00:10 adapter a Module:mathRoman.lua
 http://www.mediawiki.org/wiki/Module:mathRoman.lua
 http://www.mediawiki.org/wiki/Extension:Scribunto/Parser_interface_design
 Proposed interface summary
 20120505 19:50 function r.roman2integer( frame )
 ]]--
 
  function roman2int(rm, err)
    if ( rm == nil ) then rm = '' end 
    if ( err == nil ) then err = '' end 
    if ( rm == '' ) then return '' end 
    local v = 0 -- valeur totale
    local v1 = 0 -- valeur de derniere lettre
    local v2 = 0 -- valeur de lettre precedente
    local v3 = 0 -- valeur de lettre precedente
    local x = '-' -- caractere en cours d'evaluation
    local i = 0 -- numéro du caractere en cours d'evaluation
    local j = 0 -- numéro du caractere de reference courant (debut en Lua)
    local k = 0 -- numéro du caractere de reference courant (fin en Lua)
    local e0 = '' -- texte d'erreur
    local e1 = '' -- texte d'erreur
    local e2 = '' -- texte d'erreur
    local e3 = '' -- texte d'erreur
    local e4 = '' -- texte d'erreur
    local lst = '-MDCLXVIJ' -- caracteres autorises
    while (x ~= '') do
      v3 = v2
      v2 = v1
      v1 = 0
      x = string.sub(rm, i, i)
      if ( x == 'M' ) then v1 = 1000 end
      if ( x == 'D' ) then v1 = 500 end
      if ( x == 'C' ) then v1 = 100 end
      if ( x == 'L' ) then v1 = 50 end
      if ( x == 'X' ) then v1 = 10 end
      if ( x == 'V' ) then v1 = 5 end
      if ( x == 'I' ) then v1 = 1 end
      if ( x == 'J' ) then
        v1 = 1
        if ( i < ( string.len(rm) - 0 ) )
        then e4 = ' erreur caractere J avant la fin.' end
      end
      v = v + v1
      if ( (v1 == 5*v2) or (v1 == 10*v2) ) then v = v - (2*v2) end -- ajuster 4, 9, 40, 90 ...
      j, k = string.find(lst, x)
      if ( j == nil ) then j = -1 end 
      if ( k == nil ) then k = -1 end 
      if ( j < 1 ) then e3 = ' erreur caractere '..x..' en '..i..'.' end
      if ( (v1 > v2) and (v2 > v3) ) then e2 = ' caracteres croissants.' end
      i = i + 1
      x = string.sub(rm, i, i)
    end
    if ( v == 0 ) then e0 = ' valeur nulle.' end
    if ( v > 4999 ) then e1 = ' valeur > 4999.' end
    if ( ( e0..e1..e2..e3..e4 > '' ) and ( err > '' ) ) then 
      err = ''..err..e0..e1..e2..e3..e4 -- sortie avec les erreurs
    else
      err = '' -- sortie sans les erreurs
    end
    return v, err -- avec ou sans erreurs
  end -- function roman2int(rm, err)
 
  function romani2r(i, j)
    if ( j == nil ) then j = '' end
    local rm=''
    if ( i == 1000 ) then rm = 'M' end
    if ( i == 500 ) then rm = 'D' end
    if ( i == 100 ) then rm = 'C' end
    if ( i == 50 ) then rm = 'L' end
    if ( i == 10 ) then rm = 'X' end
    if ( i == 5 ) then rm = 'V' end
    if ( i == 1 ) then 
      rm = 'I'
      if ( j == 'J' ) then  rm = 'J' end
    end
    return rm
  end -- function romani2r(i, j)
 
  function int2roman(i, err)
    local n = 0
    if ( i == nil ) then n = 0 else n = i end -- anti null
    if ( type(n) ~= 'number' ) then n = tonumber(n) end
    if ( type(n) ~= 'number' ) then n = 0 end
    n = math.floor(n) -- input:89: bad argument #1 to 'floor' (number expected, got nil)
    -- if ( type (v) ~= 'number' ) then i = 0 end -- anti nil
    -- i = i.valueOf()
    if ( err == nil ) then err = ' ' end -- anti null, to text
    local v100 = 100 
    local v500 = v100*5 
    local v1000 = v100*10 -- cycle romain 1000, 100, 10, 1
    local v=0 
    local v1=0 
    local v2=0 
    local v3=0 -- valeurs totale, derniere, et precedentes
    local reste=0 
    local reduction=0 -- reste a convertir, derniere reduction
    --local x='-' local i=0 -- caractere courant et son numéro
    --local lst='-MDCLXVIJ' -- liste des chiffres romains
    local rm='' 
    local roman='' -- chiffre et nombre romain resultant
    local e0='' 
    local e1='' 
    local e2='' 
    local e3='' 
    local e4='' -- erreurs detectables
    if ( n > 4999 ) then
      e1 = ' valeur > 4999.'
      roman = 'ERREUR'
      n = 0
    end 
    if ( n < 1 ) then
      e2 = ' valeur < 1.'
      roman = 'ERREUR'
      n = 0
    end 
    reste = n
    -- return ' test ' -- temporaire
    while (reste > 0) do
      v3 = v2 
      v2 = v1 
      v1 = reste
      reduction = 0
      if ( reste >= v1000 ) then 
        reduction = v1000 
      elseif ( reste >= v100*9 ) then 
        reduction = v100 
        reste = reste + v100*2 
      elseif ( reste >= v500 ) then 
        reduction = v500 
      elseif ( reste >= v100*4 ) then 
        reduction = v100 
        reste = reste + v100*2 
      elseif ( reste >= v100 ) then 
        reduction = v100 
      elseif ( reste >= 1000 ) then 
        v100 = 100 
        v1000 = 1000 
        reduction = v1000 
      end
      rm = romani2r(reduction)
      roman = roman..rm
      reste = reste - reduction
      if ( reste < v100 ) then 
        if ( v100 >= 10 ) then 
          v100 = v100/10 
          v500 = v100*5 
          v1000 = v100*10
        end
      end
    end
    -- if ( v == 0 ) then e0 = ' valeur nulle.' end
    -- if ( v > 4999 ) then e1 = ' valeur > 4999.' end
    if ( ( e0..e1..e2..e3..e4 > '' ) and ( err > '' ) ) then 
      err = ''..err..e0..e1..e2..e3..e4 -- sortie avec les erreurs
    else
      err = '' -- sortie sans les erreurs
    end
    return roman, err -- avec ou sans erreurs
  end -- function int2roman(in, err)
 
  function testerUnRomain(r1, view) 
    if ( r1 == nil ) then r1 = '' end
    if ( view == nil ) then view = '' end
    if ( view == '' ) then view = '%s' end
    local i, erri = roman2int(r1, ' Erreur r2i : ')
    local rm, errm = int2roman(i, ' Erreur i2r : ')
    local s = r1 .. '=' .. i .. '=' .. rm
    if ( erri == nil ) then erri = '' end
    if ( errm == nil ) then errm = '' end
    if ( ( erri ~= '' ) or ( errm ~= '' ) ) then
        s = s .. ' -> ' .. erri .. errm
    end
    return string.format(view, s)
    -- return string.format("Hello, %s!", s)
  end -- function testerUnRomain(r1, view)
 
  function erreurUnRomain(r1, view)
    if ( r1 == nil ) then r1 = '' end
    if ( view == nil ) then view = '' end
    if ( view == '' ) then view = '%s' end
    local i, erri = roman2int(r1, ' Erreur r2i : ')
    local s = ' - ' .. r1 .. '=' .. i
    if ( erri == nil ) then erri = '' end
    if ( erri ~= '' ) then
        s = s .. ' -> ' .. erri
    end
    return string.format(view, s)
    -- return string.format("Hello, %s!", s)
  end -- function erreurUnRomain(r1, view)
 
  function testerDesRomains(view)
      if ( view == nil ) then view = '' end
      if ( view == '' ) then view = '%s' end
      local s = ''
      s = s .. testerUnRomain('XIJ', view)
      s = s .. testerUnRomain('XIJ', view)
      s = s .. testerUnRomain('MCXI', view)
      s = s .. testerUnRomain('MCDXLIV', view)
      s = s .. testerUnRomain('MDCLXVI', view)
      s = s .. testerUnRomain('MCMXCIX', view)
      s = s .. testerUnRomain('MMCCXXII', view)
      s = s .. testerUnRomain('MMMMCMXCIX', view)
      -- Nombres avec erreurs
      s = s .. testerUnRomain('i', view)
      s = s .. testerUnRomain('ERREURS', view)
      s = s .. testerUnRomain('XIA', view)
      s = s .. testerUnRomain('XJI', view)
      s = s .. testerUnRomain('IXC', view)
      s = s .. testerUnRomain('VLD', view)
      s = s .. testerUnRomain('MMMMM', view)
      s = s .. testerUnRomain('MMMMMYJXC', view)
      s = s .. testerUnRomain('', view)
      s = s .. testerUnRomain(nil)
      s = s .. erreurUnRomain('ERREURS', view)
      s = s .. erreurUnRomain('XIA', view)
      s = s .. erreurUnRomain('XJI', view)
      s = s .. erreurUnRomain('IXC', view)
      s = s .. erreurUnRomain('VLD', view)
      s = s .. erreurUnRomain('MMMMM', view)
      s = s .. erreurUnRomain('MMMMMYJXC', view)
      return s
  end -- function testerDesRomains(view) 
 
 --  testerDesRomains('x') -- lance le test
 
 -- Interface http://scribunto.wmflabs.org/
 local p = {}
 function p.hello()
     -- {{#invoke:MathRoman.lua|hello}}
     return 'Hello, world!'
 end
 function p.roman2integer(frame)
     -- { {#invoke:MathRoman.lua|roman2integer| MMXIJ } }
     local r = frame.args[1]
     local i, erri = roman2int(r, ' Error r2i : ')
     return i
 end
 function p.r2i(frame) -- shortcut of roman2integer
     -- { {#invoke:MathRoman.lua|r2i| MMXIJ } }
     return p.roman2integer(frame)
 end
 function p.integer2roman(frame)
     -- { {#invoke:MathRoman.lua|integer2roman| 2012 } }
     local i = frame.args[1]
     local r, errr = int2roman(i, ' Error i2r : ')
     return r
 end
 function p.i2r(frame) -- shortcut of integer2roman
     -- { {#invoke:MathRoman.lua|i2r| MMXIJ } }
     return p.integer2roman(frame)
 end
 function p.testRomans(frame)
     -- { {#invoke:MathRoman.lua|testRomans|': %s<br/>'} }
     local view = frame.args[1]
     if ( view == nil ) then view = '' end
     if ( view == '' ) then view = '%s' end
     local s = testerDesRomains(view)
     return s
 end
 function p.testText(formater, text, n)
     -- { {#invoke:MathRoman.lua|testText|': %s<br/>'|Text under test. |3} }
     local s = ''
     local N = tonumber(n)
     while ( N > 0 ) do
         s = s .. string.format(formater, text)
         N = N - 1
     end
     return s
 end
 return p