コード例 #1
0
ファイル: Validate.cs プロジェクト: IDjinn/Romano
        private static Exception?CheckRepeatedDigits(string roman, RomanizerOptions options)
        {
            var allowFourSum     = options.HasFlag(RomanizerOptions.ALLOW_FOUR_SEQUENTIAL_DIGITS);
            var allowMultipleSum = options.HasFlag(RomanizerOptions.ALLOW_MULTIPLE_SEQUENTIAL_DIGITS);

            for (var i = 0; i < roman.Length; i++)
            {
                var current       = roman[i];
                var totalRepeated = (byte)roman.Skip(i).TakeWhile(digit => digit == current).Count();
                switch (totalRepeated)
                {
                case <= 3:
                    continue;

                case 4 when !allowFourSum:
                    return(new ArithmeticAdditionException(
                               roman, current, totalRepeated,
                               $"Roman number '{roman}' with multiple repeated digits of '{current}' with total '{totalRepeated}', so it is invalid roman number. If you want sum 4 digits you need allow this in options entry."));

                case > 4 when !allowMultipleSum:
                    return(new ArithmeticAdditionException(
                               roman, current, totalRepeated,
                               $"Roman number '{roman}' with multiple repeated digits of '{current}' with total '{totalRepeated}', so it is invalid roman number. If you want sum more than 4 digits you need allow this in options entry."));
                }
            }

            return(null);
        }
コード例 #2
0
ファイル: Humanizer.cs プロジェクト: IDjinn/Romano
        internal static ushort HumanizeUnsafe(string roman, RomanizerOptions options)
        {
            ushort total = 0, index = 0;

            do
            {
                var number       = roman[index];
                var left         = Util.LeftOrNullUnsafe(roman, index);
                var right        = Util.RightOrNullUnsafe(roman, index);
                var currentValue = Util.ConvertSingleRomanToDecimal(number);
                var rightDecimal = CheckRightDecimalSpecialRules(options, left, right, number);
                index++;

                var hasRightValue = rightDecimal > 0;
                var needSubtractFromRightDecimal = hasRightValue && rightDecimal > currentValue;
                if (needSubtractFromRightDecimal)
                {
                    total += (ushort)(rightDecimal - currentValue);
                    index++;
                    continue;
                }

                total += currentValue;
            } while (index < roman.Length);

            return(total);
        }
コード例 #3
0
ファイル: Validate.cs プロジェクト: IDjinn/Romano
        public static bool IsValidRoman(string?roman, RomanizerOptions options = RomanizerOptions.DEFAULT_STRICT)
        {
            if (roman is null)
            {
                return(false);
            }

            if (string.IsNullOrEmpty(roman.Trim().ToUpper()))
            {
                return(false);
            }

            var hasInvalidRomanDigit = roman.All(digit => Constants.ROMAN_NUMBERS.ContainsKey(digit)) is false;

            if (hasInvalidRomanDigit)
            {
                return(false);
            }

            var hasRepeatedDigits = CheckRepeatedDigits(roman.Trim().ToUpper(), options) is not null;

            if (hasRepeatedDigits)
            {
                return(false);
            }

            return(true);
        }
コード例 #4
0
ファイル: Validate.cs プロジェクト: IDjinn/Romano
        /// <summary>
        /// Validate a roman number
        /// </summary>
        /// <param name="roman">Roman number input</param>
        /// <param name="options">Options to parse this roman number</param>
        /// <returns>Valid roman number</returns>
        /// <exception cref="ArgumentNullException">Roman number can not be a null string</exception>
        /// <exception cref="ArgumentException">Invalid roman digit</exception>
        /// <exception cref="ArithmeticAdditionException">Parse not allowed by rules options</exception>
        public static string RomanNumber(string?roman, RomanizerOptions options)
        {
            if (string.IsNullOrEmpty(roman))
            {
                throw new ArgumentNullException(nameof(roman));
            }

            string cleanRoman = roman.Trim().ToUpper();

            if (string.IsNullOrEmpty(cleanRoman))
            {
                throw new ArgumentNullException(nameof(roman));
            }

            var hasInvalidRomanDigit = roman.All(digit => Constants.ROMAN_NUMBERS.ContainsKey(digit)) is false;

            if (hasInvalidRomanDigit)
            {
                throw new ArgumentException($"Invalid roman char: {roman}");
            }

            var exception         = CheckRepeatedDigits(cleanRoman, options);
            var hasRepeatedDigits = exception is not null;

            if (hasRepeatedDigits)
            {
                throw exception !;
            }

            return(cleanRoman);
        }
コード例 #5
0
        internal static string RomanizeUnsafe(ushort number, RomanizerOptions options = RomanizerOptions.DEFAULT_STRICT)
        {
            StringBuilder roman = new(MAX_VALUE_ROMAN.Length);

            do
            {
                for (var i = 0; i < romanNumbersReversed.Count(); i++)
                {
                    var(romanDigit, decimalDigit) = romanNumbersReversed.ElementAt(i);
                    if (number < decimalDigit)
                    {
                        continue;
                    }

                    var count = (ushort)Math.Round((double)(number / decimalDigit));

                    /*
                     * Special rule
                     *
                     * When the number have free 4 units, need subtract then by higher value for not throw 4 sum limit.
                     *
                     * Example: IIII => IV
                     */
                    var isSpecialCountRule = count == 4 && !options.HasFlag(RomanizerOptions.ALLOW_FOUR_SEQUENTIAL_DIGITS);
                    if (isSpecialCountRule)
                    {
                        var higherValueIndex = i - 1;
                        var(rightRomanDigit, rightDigit) = romanNumbersReversed.ElementAtOrDefault(higherValueIndex);
                        var existRightValue = rightRomanDigit != 0 && rightDigit > 0;

                        /*
                         * Need check if have higher value to subtract free units
                         */
                        if (existRightValue)
                        {
                            roman.Append(romanDigit);
                            roman.Append(rightRomanDigit);
                            number -= (ushort)(decimalDigit * count);
                            break;
                        }
                    }

                    /*
                     * Special rule end
                     */

                    for (var j = 0; j < count; j++)
                    {
                        roman.Append(romanDigit);
                    }
                    number -= (ushort)(decimalDigit * count);
                    break;
                }
            } while (number > 0);

            return(roman.ToString());
        }
コード例 #6
0
ファイル: Humanizer.cs プロジェクト: IDjinn/Romano
        private static ushort CheckRightDecimalSpecialRules(RomanizerOptions options, char?left, char?right, char number)
        {
            if (right is not null && right.HasValue)
            {
                var rightDecimal          = Util.ConvertSingleRomanToDecimal(right.Value);
                var needCheckSpecialRules = left.HasValue && right.HasValue;
                if (needCheckSpecialRules)
                {
                    CheckSpecialRules(left !.Value, right !.Value, number, rightDecimal, options);
                }

                return(rightDecimal);
            }
            return(0);
        }
コード例 #7
0
ファイル: Humanizer.cs プロジェクト: IDjinn/Romano
        private static void CheckSpecialRules(char left, char right, char current, int rightValue,
                                              RomanizerOptions options)
        {
            var isNotStrict = !options.HasFlag(RomanizerOptions.DEFAULT_STRICT);

            if (isNotStrict)
            {
                return;
            }

            var isAddition = Util.ConvertSingleRomanToDecimal(current) >= rightValue;

            if (isAddition)
            {
                CheckAdditionSpecialRules(current, rightValue, options);
            }
            else
            {
                CheckSubtractionSpecialRules(left, right, current, options);
            }
        }
コード例 #8
0
 public void InvalidRomanToHumanTest(string roman, Type @throw, RomanizerOptions options = RomanizerOptions.DEFAULT_STRICT)
 {
     Assert.Throws(@throw, () => Romano.Humanize(roman, options) as object);
     // Assert.False(Romano.IsValidRoman(roman));
 }
コード例 #9
0
ファイル: Util.cs プロジェクト: IDjinn/Romano
 public static char?RightOrNull(string roman, int index, RomanizerOptions options)
 {
     return(RightOrNullUnsafe(Validate.RomanNumber(roman, options), index));
 }
コード例 #10
0
ファイル: Humanizer.cs プロジェクト: IDjinn/Romano
 private static void CheckSubtractionSpecialRules(char left, char right, char current, RomanizerOptions options)
 {
     if (JUST_ONE_CAN_SUBSTRACT.Contains(right) && current != 'I')
     {
         throw new ArithmeticSubtractionException(left, right, $"Invalid left '{left}' right '{right}' with strict rule (default) enabled you cant subtract '{right}' by '{left}'");
     }
     if (JUST_TEN_CAN_SUBSTRACT.Contains(right) && current != 'X')
     {
         throw new ArithmeticSubtractionException(left, right, $"Invalid left '{left}' right '{right}' with strict rule (default) enabled you cant subtract '{right}' by '{left}'");
     }
 }
コード例 #11
0
ファイル: Humanizer.cs プロジェクト: IDjinn/Romano
 private static void CheckAdditionSpecialRules(char current, int rightValue, RomanizerOptions options)
 {
 }
コード例 #12
0
ファイル: Humanizer.cs プロジェクト: IDjinn/Romano
 public static ushort Humanize(string roman, RomanizerOptions options = RomanizerOptions.DEFAULT_STRICT)
 {
     return(HumanizeUnsafe(Validate.RomanNumber(roman, options), options));
 }
コード例 #13
0
        public static string Romanize(ushort number, RomanizerOptions options = RomanizerOptions.DEFAULT_STRICT)
        {
            var validNumber = Validate.HumanNumber(number);

            return(RomanizeUnsafe(validNumber, options));
        }
コード例 #14
0
 public static string Romanize(sbyte number, RomanizerOptions options = RomanizerOptions.DEFAULT_STRICT)
 {
     return(Romanize((ushort)number, options));
 }
コード例 #15
0
 public static ushort Humanize(char roman, RomanizerOptions options = RomanizerOptions.DEFAULT_STRICT)
 {
     return(Humanize(roman.ToString(), options));
 }