using System; using System.Text; namespace NzbDrone.Core.Parser.RomanNumerals { /// /// Represents the numeric system used in ancient Rome, employing combinations of letters from the Latin alphabet to signify values. /// Implementation adapted from: http://www.c-sharpcorner.com/Blogs/14255/converting-to-and-from-roman-numerals.aspx /// public class RomanNumeral : IComparable, IComparable, IEquatable, IRomanNumeral { /// /// The numeric value of the roman numeral. /// private readonly int _value; /// /// Represents the smallest possible value of an . This field is constant. /// public static readonly int MinValue = 1; /// /// Represents the largest possible value of an . This field is constant. /// public static readonly int MaxValue = 3999; private static readonly string[] Thousands = { "MMM", "MM", "M" }; private static readonly string[] Hundreds = { "CM", "DCCC", "DCC", "DC", "D", "CD", "CCC", "CC", "C" }; private static readonly string[] Tens = { "XC", "LXXX", "LXX", "LX", "L", "XL", "XXX", "XX", "X" }; private static readonly string[] Units = { "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I" }; /// /// Initializes a new instance of the class. /// public RomanNumeral() { _value = 1; } /// /// Initializes a new instance of the class. /// /// The value. public RomanNumeral(int value) { _value = value; } /// /// Initializes a new instance of the class. /// /// The roman numeral. public RomanNumeral(string romanNumeral) { if (TryParse(romanNumeral, out var value)) { _value = value; } } /// /// Converts this instance to an integer. /// /// A numeric int representation. public int ToInt() { return _value; } /// /// Converts this instance to a long. /// /// A numeric long representation. public long ToLong() { return _value; } /// /// Converts the string representation of a number to its 32-bit signed integer equivalent. A return value indicates whether the conversion succeeded. /// /// A string containing a number to convert. /// When this method returns, contains the 32-bit signed integer value equivalent of the number contained in , /// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the parameter is null or /// , is not of the correct format, or represents a number less than or greater than . This parameter is passed uninitialized. 1 /// /// true if was converted successfully; otherwise, false. /// public static bool TryParse(string text, out int value) { value = 0; if (string.IsNullOrEmpty(text)) { return false; } text = text.ToUpper(); var len = 0; for (var i = 0; i < 3; i++) { if (text.StartsWith(Thousands[i])) { value += 1000 * (3 - i); len = Thousands[i].Length; break; } } if (len > 0) { text = text.Substring(len); len = 0; } for (var i = 0; i < 9; i++) { if (text.StartsWith(Hundreds[i])) { value += 100 * (9 - i); len = Hundreds[i].Length; break; } } if (len > 0) { text = text.Substring(len); len = 0; } for (var i = 0; i < 9; i++) { if (text.StartsWith(Tens[i])) { value += 10 * (9 - i); len = Tens[i].Length; break; } } if (len > 0) { text = text.Substring(len); len = 0; } for (var i = 0; i < 9; i++) { if (text.StartsWith(Units[i])) { value += 9 - i; len = Units[i].Length; break; } } if (text.Length > len) { value = 0; return false; } return true; } /// /// Converts a number into a roman numeral. /// /// The number. /// private static string ToRomanNumeral(int number) { RangeGuard(number); int thousands, hundreds, tens, units; thousands = number / 1000; number %= 1000; hundreds = number / 100; number %= 100; tens = number / 10; units = number % 10; var sb = new StringBuilder(); if (thousands > 0) { sb.Append(Thousands[3 - thousands]); } if (hundreds > 0) { sb.Append(Hundreds[9 - hundreds]); } if (tens > 0) { sb.Append(Tens[9 - tens]); } if (units > 0) { sb.Append(Units[9 - units]); } return sb.ToString(); } /// /// Returns the Roman numeral that was passed in as either an Arabic numeral /// or a Roman numeral. /// /// A representing a Roman Numeral public string ToRomanNumeral() { return ToString(); } /// /// Determines whether a given number is within the valid range of values for a roman numeral. /// /// The number to validate. /// /// $Roman numerals can not be larger than {MaxValue}. /// or /// $Roman numerals can not be smaller than {MinValue}. /// private static void RangeGuard(int number) { if (number > MaxValue) { throw new ArgumentOutOfRangeException(nameof(number), number, $"Roman numerals can not be larger than {MaxValue}."); } if (number < MinValue) { throw new ArgumentOutOfRangeException(nameof(number), number, $"Roman numerals can not be smaller than {MinValue}."); } } /// /// Implements the operator *. /// /// The first numeral. /// The second numeral. /// /// The result of the operator. /// public static RomanNumeral operator *(RomanNumeral firstNumeral, RomanNumeral secondNumeral) { return new RomanNumeral(firstNumeral._value * secondNumeral._value); } /// /// Implements the operator /. /// /// The numerator. /// The denominator. /// /// The result of the operator. /// public static RomanNumeral operator /(RomanNumeral numerator, RomanNumeral denominator) { return new RomanNumeral(numerator._value / denominator._value); } /// /// Implements the operator +. /// /// The first numeral. /// The second numeral. /// /// The result of the operator. /// public static RomanNumeral operator +(RomanNumeral firstNumeral, RomanNumeral secondNumeral) { return new RomanNumeral(firstNumeral._value + secondNumeral._value); } /// /// Implements the operator -. /// /// The first numeral. /// The second numeral. /// /// The result of the operator. /// public static RomanNumeral operator -(RomanNumeral firstNumeral, RomanNumeral secondNumeral) { return new RomanNumeral(firstNumeral._value - secondNumeral._value); } /// /// /// The object. /// public int CompareTo(object obj) { if (obj is sbyte || obj is byte || obj is short || obj is ushort || obj is int || obj is uint || obj is long || obj is ulong || obj is float || obj is double || obj is decimal) { var value = (int)obj; return _value.CompareTo(value); } else if (obj is string) { var numeral = obj as string; if (TryParse(numeral, out var value)) { return _value.CompareTo(value); } } return 0; } /// /// Compares to. /// /// The other. /// public int CompareTo(RomanNumeral other) { return _value.CompareTo(other._value); } /// /// Equalses the specified other. /// /// The other. /// public bool Equals(RomanNumeral other) { return _value == other._value; } /// /// Returns the Roman Numeral which was passed to this Instance /// during creation. /// /// /// A that represents a Roman Numeral. /// public override string ToString() { return ToRomanNumeral(_value); } } }