Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// Класс предназначен для преобразований арабских чисел в римские и обратно
- /// </summary>
- /// <remarks>
- /// <para>Класс изначально содержит алфавит римских чисел, способных определять арабские числа от 1 до 39999</para>
- /// <para>Если необходимо расширить диапазон, то можно определить дополнительные обозначения для римских чисел, используя
- /// поле <see cref="БазовыеРимскиеЧисла"/>БазовыеРимскиеЧисла</remarks>
- public static class РимскоеЧисло
- {
- /// <summary>
- /// Алфавит базовых римских чисел
- /// <para>Алфавит построен в виде словаря. Ключем словаря является арабское число (int), значением - соответствующее ему
- /// римское число (string)</para>
- /// </summary>
- /// <remarks>
- /// <para>Содержит римское обозначения арабских чисел 1*,4*,5*,9* - где "*"представляет собой 0...N нулей</para>
- /// <para>При создании содержит в себе обозначение чисел от 1 до 10000 (I...ↂ) Так как в римском числе один символ не может
- /// встречаться более трех раз, то изначально можно преобразовать в римский формат числа от 1 до 39999.</para>
- /// <para>Если Вы хотите иметь возможность работать с большим количеством римских чисел, то вы должны добавить в список
- /// дополнительные обозначения начиная с 40000 не пропуская элементы 1*,4*,5*,9*.</para>
- /// </remarks>
- public static SortedList<int, string> БазовыеРимскиеЧисла { get; set; }
- static РимскоеЧисло()
- {
- БазовыеРимскиеЧисла = new SortedList<int, string>(17);
- БазовыеРимскиеЧисла.Add(1, "I");
- БазовыеРимскиеЧисла.Add(4, "IV");
- БазовыеРимскиеЧисла.Add(5, "V");
- БазовыеРимскиеЧисла.Add(9, "IX");
- БазовыеРимскиеЧисла.Add(10, "X");
- БазовыеРимскиеЧисла.Add(40, "XL");
- БазовыеРимскиеЧисла.Add(50, "L");
- БазовыеРимскиеЧисла.Add(90, "XC");
- БазовыеРимскиеЧисла.Add(100, "C");
- БазовыеРимскиеЧисла.Add(400, "CD");
- БазовыеРимскиеЧисла.Add(500, "D");
- БазовыеРимскиеЧисла.Add(900, "CM");
- БазовыеРимскиеЧисла.Add(1000, "M");
- БазовыеРимскиеЧисла.Add(4000, "Mↁ");
- БазовыеРимскиеЧисла.Add(5000, "ↁ");
- БазовыеРимскиеЧисла.Add(9000, "Mↂ");
- БазовыеРимскиеЧисла.Add(10000, "ↂ");
- }
- /// <summary>
- /// Рассчитывает максимально возможное римское число для текущего алфавита римских чисел.
- /// </summary>
- /// <returns>Максимально возможное римское число</returns>
- public static uint МаксимальноеРимскоеЧисло()
- {
- int последнееЧисло = БазовыеРимскиеЧисла.Keys.Last();
- int числоБезНулей = int.Parse(последнееЧисло.ToString().Replace('0','\0'));
- int предварительное=0;
- switch (числоБезНулей)
- {
- case 1:
- предварительное = последнееЧисло * 4 - 1;
- break;
- case 4:
- case 9:
- предварительное = последнееЧисло;
- break;
- case 5:
- предварительное = последнееЧисло + последнееЧисло / 5 * 3;
- break;
- default:
- break;
- }
- return uint.Parse(предварительное.ToString().Replace('0', '9'));;
- }
- /// <summary>
- /// Конвентирует целое число в римское число
- /// </summary>
- /// <param name="числоАраб">Арабское число, которое необходимо преобразовать в римскую запись</param>
- /// <exception cref="ArgumentOutOfRangeException">Генерируется когда в качестве параметра передано число равное "0"
- /// или число большее чем максимальная римское число.</exception>
- /// <returns>Строку, представляющую собой римской число</returns>
- public static string АрабскоеВРимское(this int числоАраб)
- {
- StringBuilder числоРимское = new StringBuilder();
- //Исключаем знак "-" из арабского числа и делаем его первым символом римского числа
- if (числоАраб < 0)
- {
- числоРимское.Append("-");
- числоАраб = -числоАраб;
- }
- if (числоАраб == 0)
- throw new ArgumentOutOfRangeException("числоАраб", числоАраб,
- "Недопустимое значение аргумента: римские числа не могут быть равными\"0\"");
- else if (числоАраб > МаксимальноеРимскоеЧисло())
- throw new ArgumentOutOfRangeException("числоАраб", числоАраб,
- string.Format("Недопустимое значение аргумента: невозможно задать римское число большее чем {0}",
- МаксимальноеРимскоеЧисло()));
- //Раскладываем арабское число на составляющие его римские числа и объединяем их в одну строку
- var необходимыеБазовыеРимскиеЧисла =
- from к in БазовыеРимскиеЧисла.Keys
- where к <= числоАраб
- orderby к descending
- select к;
- foreach (int тек in необходимыеБазовыеРимскиеЧисла)
- {
- while ((числоАраб / тек) >= 1)
- {
- числоАраб -= тек;
- числоРимское.Append(БазовыеРимскиеЧисла[тек]);
- }
- }
- return числоРимское.ToString();
- }
- /// <summary>
- /// Конвентирует римское число в арабское
- /// </summary>
- /// <param name="числоРимское">Римское число, которое необходимо преобразовать в тип int</param>
- /// <exception cref="FormatException">Генерируется когда в качестве параметра передано число не являющееся римским</exception>
- /// <returns>Целое число, представляющее собой арабскую запись римского числа</returns>
- public static int РимскоеВАрабское(this string числоРимское)
- {
- int числоАраб = 0;
- sbyte отрицательное = 1;
- string рим = числоРимское.Trim();
- if (рим[0] == '-')
- {
- отрицательное = -1;
- рим = рим.Substring(1);
- }
- StringBuilder шаблонРимскогоНомера = new StringBuilder();
- foreach (int к in БазовыеРимскиеЧисла.Keys)
- {
- int индекс = БазовыеРимскиеЧисла.Keys.IndexOf(к);
- string квантификатор="?";
- if (индекс == 0 || (индекс % 4) == 0)
- квантификатор="{0,3}";
- шаблонРимскогоНомера.Insert(0, string.Format("(?<{0}>({1}){2})?", к.ToString(),
- БазовыеРимскиеЧисла[к], квантификатор));
- }
- //Игнорировать регистр + соответствие должно начинаться с начала строки
- шаблонРимскогоНомера.Insert(0, "(?i)^");
- //Соответствие должно обнаруживаться в конце строки
- шаблонРимскогоНомера.Append("$");
- //Упрощенная проверка. Не проверяет таких ошибок как IVII
- if (!Regex.IsMatch(рим, шаблонРимскогоНомера.ToString()))
- throw new FormatException(string.Format("Текст \"{0}\" не является римским числом",числоРимское));
- Match число = Regex.Match(рим, шаблонРимскогоНомера.ToString());
- foreach (int к in БазовыеРимскиеЧисла.Keys)
- {
- числоАраб += число.Groups[к.ToString()].Length / БазовыеРимскиеЧисла[к].Length * к;
- }
- return числоАраб * отрицательное;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement