About me

About

2011-09-30

Numeração romana e sed.

A lógica da numeração romana é curiosa porque não se baseia em nenhuma base, embora o 5 e o 10 tenham um papel tipo base.

Outro aspecto interessante da sua lógica é que obedece a um padrão greedy. Como tal podem-se usar expressões regulares para converter de/para romano. Entra o sed.

  • conversão de romano para decimal

    #! /bin/sed -f

    # fr_roman.sed -- from roman (to decimal)
    # Carlos Duarte, 980707

    # usage: echo MCMXCVIII | sed -f fr_roman.sed
    # output: 1998
    #
    # converts roman literals to decimal
    # some input error checking is done, but not all cases are covered
    # (bigger constructions following smallers, for instance)
    #

    # build table, all possible constructs that evaluate to [1-9]0* are here
    1{
    x
    s/$/0/
    s/$/I1/
    s/$/II2/
    s/$/III3/
    s/$/IV4/
    s/$/V5/
    s/$/VI6/
    s/$/VII7/
    s/$/VIII8/
    s/$/IX9/
    s/$/X10/
    s/$/XX20/
    s/$/XXX30/
    s/$/XL40/
    s/$/L50/
    s/$/LX60/
    s/$/LXX70/
    s/$/LXXX80/
    s/$/XC90/
    s/$/C100/
    s/$/CC200/
    s/$/CCC300/
    s/$/CD400/
    s/$/D500/
    s/$/DC600/
    s/$/DCC700/
    s/$/DCCC800/
    s/$/CM900/
    s/$/M1000/
    s/$/MM2000/
    s/$/MMM3000/
    x
    }

    # converts from MMXXII to 2000,20,2, from lookup table
    s/^/\
    /
    G

    ta
    :a
    s/\n\(..*\)\(.*\n.*[0-9]\)\1\([1-9]0*\)/\3,\
    \2\1\3/
    tb

    s/\n/>>> error:/
    s/\n.*//
    #q
    b

    :b
    /\n\n/!ba
    s/\n\n.*$//

    # convert from 2000,20,2, to 2022. this is not trivial!
    #
    # steps:
    # 2000,20,2, -> 2000<20>2, <20> is the work digit
    :d
    s/,/</
    te
    :e
    s/,/>/
    tf

    # exit point here: contains `2022,' so, remove the `,' and go
    s/.$//
    b

    # 2000<20>2, -> 2000,:20<20>2, : is the cursor for changing the 20 in ,:20
    # into 00 (for later, remove these from 2000)
    :f
    s/<\(.*\)>/,:\1&/

    # 2000,:20<20>2, -> 2000,00:<20>2,
    tc
    :c
    s/:[0-9]/0:/
    tc

    # 2000,00:<20>2, -> 2020,2, convert next digit
    s/\(0*\),\1:<//
    s/>/,/
    bd
  • conversão de decimal para romano

    #! /bin/sed -f

    # to_roman.sed -- converts decimal to roman
    # Carlos Duarte, 980707

    # do not perform error checking
    # converts input treated as arabic decimals, to roman literal
    #
    # eg: echo 1998 | sed -f to_roman.sed
    # outputs: MCMXCVIII
    #

    # build table, all possible constructs that evaluate to [1-9]0* are here
    1{
    x
    s/$/1I/
    s/$/2II/
    s/$/3III/
    s/$/4IV/
    s/$/5V/
    s/$/6VI/
    s/$/7VII/
    s/$/8VIII/
    s/$/9IX/
    s/$/10X/
    s/$/20XX/
    s/$/30XXX/
    s/$/40XL/
    s/$/50L/
    s/$/60LX/
    s/$/70LXX/
    s/$/80LXXX/
    s/$/90XC/
    s/$/100C/
    s/$/200CC/
    s/$/300CCC/
    s/$/400CD/
    s/$/500D/
    s/$/600DC/
    s/$/700DCC/
    s/$/800DCCC/
    s/$/900CM/
    s/$/1000M/
    s/$/2000MM/
    s/$/3000MMM/
    x
    }

    s/.*/:&:/
    ta
    :a
    s/:.\([^:]*\):$/&\1:/
    ta

    :c
    s/:\(.\)/\1,/
    tb
    :b
    s/,[0-9]/0,/
    tb
    /,::$/bd
    s/,/;/
    bc

    :d
    s/...$/;/
    s/;00*//g
    s/^/,/

    G
    te
    :e
    s/,\([^;]*\);\(.*\n.*\)\1\([IVXLCDM][IVXLCDM]*\)/\3,\2\1\3/
    te
    s/.\n.*//
  • compilador de romano para expressão numérica do equivalente decimal

    • echo MCXLIII | sed -f from_roman.sed => 1000+100+40+1+1+1
    • echo MCMLXXXI | sed -f from_roman.sed => 1000+900+50+10+10+10+1
    #! /bin/sed -f

    # from_roman.sed -- output bc(1) code that convert roman to decimal
    # Carlos Duarte, 980707

    # usage: echo MCXLIII | sed -f from_roman.sed | bc

    s/$/\
    0M1000CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1/

    s/^/\
    /
    ta
    :a
    s/\n\(..\)\(.*\n.*[0-9]\)\1\([1-9]0*\)/\3+\
    \2\1\3/
    tb
    s/\n\(.\)\(.*\n.*[0-9]\)\1\([1-9]0*\)/\3+\
    \2\1\3/
    tb

    s/\n/0; ">>> error:/
    s/\n.*/"/
    #q
    b

    :b
    /\n\n/!ba
    s/.\n\n.*$//

Sem comentários:

Enviar um comentário