Converting integers to roman numerals

前端 未结 29 2515
走了就别回头了
走了就别回头了 2020-12-02 09:16

I\'m trying to write a function that converts numbers to roman numerals. This is my code so far; however, it only works with numbers that are less than 400. Is there a quick

29条回答
  •  长情又很酷
    2020-12-02 09:53

    This is actually quite a fun problem, and based on the reverse example on dofactory.com (turning roman numerals to decimals) its quite easy to reverse the pattern, and perhaps improve it a little. This code will support numbers from 1 to 3999999.

    Begin with a context class, this defines the I/O of the parser

    public class Context
    {
        private int _input;
        private string _output;
    
        public Context(int input)
        {
            this._input = input;
        }
    
        public int Input
        {
            get { return _input; }
            set { _input = value; }
        }
    
        public string Output
        {
            get { return _output; }
            set { _output = value; }
        }
    }
    

    And an abstract expression, which defines the parsing operation

    public abstract class Expression
    {
        public abstract void Interpret(Context value);
    }
    

    Now, you need an abstract terminal expression, which defines the actual operation that will be performed:

    public abstract class TerminalExpression : Expression
    {
        public override void Interpret(Context value)
        {
            while (value.Input - 9 * Multiplier() >= 0)
            {
                value.Output += Nine();
                value.Input -= 9 * Multiplier();
            }
            while (value.Input - 5 * Multiplier() >= 0)
            {
                value.Output += Five();
                value.Input -= 5 * Multiplier();
            }
            while (value.Input - 4 * Multiplier() >= 0)
            {
                value.Output += Four();
                value.Input -= 4 * Multiplier();
            }
            while (value.Input - Multiplier() >= 0)
            {
                value.Output += One();
                value.Input -= Multiplier();
            }
        }
    
        public abstract string One();
        public abstract string Four();
        public abstract string Five();
        public abstract string Nine();
        public abstract int Multiplier();
    }
    

    Then, classes which define the behaviour of roman numerals (note, ive used the convention of lowercase where roman numerals use a bar over the letter to denote 1000 times)

    class MillionExpression : TerminalExpression
    {
        public override string One() { return "m"; }
        public override string Four() { return ""; }
        public override string Five() { return ""; }
        public override string Nine() { return ""; }
        public override int Multiplier() { return 1000000; }
    }
    class HundredThousandExpression : TerminalExpression
    {
        public override string One() { return "c"; }
        public override string Four() { return "cd"; }
        public override string Five() { return "d"; }
        public override string Nine() { return "cm"; }
        public override int Multiplier() { return 100000; }
    }
    class ThousandExpression : TerminalExpression
    {
        public override string One() { return "M"; }
        public override string Four() { return "Mv"; }
        public override string Five() { return "v"; }
        public override string Nine() { return "Mx"; }
        public override int Multiplier() { return 1000; }
    }
    class HundredExpression : TerminalExpression
    {
        public override string One() { return "C"; }
        public override string Four() { return "CD"; }
        public override string Five() { return "D"; }
        public override string Nine() { return "CM"; }
        public override int Multiplier() { return 100; }
    }
    class TenExpression : TerminalExpression
    {
        public override string One() { return "X"; }
        public override string Four() { return "XL"; }
        public override string Five() { return "L"; }
        public override string Nine() { return "XC"; }
        public override int Multiplier() { return 10; }
    }
    class OneExpression : TerminalExpression
    {
        public override string One() { return "I"; }
        public override string Four() { return "IV"; }
        public override string Five() { return "V"; }
        public override string Nine() { return "IX"; }
        public override int Multiplier() { return 1; }
    }
    

    Almost there, we need a Non-terminal expression which contains the parse tree:

    public class DecimalToRomaNumeralParser : Expression
    {
        private List expressionTree = new List()
                                                      {
                                                          new MillionExpression(),
                                                          new HundredThousandExpression(),
                                                          new TenThousandExpression(),
                                                          new ThousandExpression(),
                                                          new HundredExpression(),
                                                          new TenExpression(),
                                                          new OneExpression()
                                                      };
    
        public override void Interpret(Context value)
        {
            foreach (Expression exp in expressionTree)
            {
                 exp.Interpret(value);
            }
        }
    }
    

    Lastly, the client code:

    Context ctx = new Context(123);
    var parser = new DecimalToRomaNumeralParser();
    parser.Interpret(ctx);
    Console.WriteLine(ctx.Output); // Outputs CXXIII
    

    Live example: http://rextester.com/rundotnet?code=JJBYW89744

提交回复
热议问题