Доброе время суток, Хабраюзер.
Разрабатывая в основном для платформы J2ME, я всегда старался вносить какие то изюминки в свои проекты. Так, однажды, мне понадобилось выделить пункты меню.
Стандартное решение, через тире или пронумеровав их, использовать не очень хотелось, но другие варианты тогда у меня отсутствовали. Обдумывая как бы лучше оформить эти пункты, я случайно наткнулся на свою старую школьную тетрадку по истории, в которой пункты были пронумерованы с использованием римских цифр. Бинго!
Стоит признаться, на то время моих познаний в римских цифрах хватало только для подсчета до второго-третьего десятка. Что вообще то для нумерации пунктов должно было хватить. Но как любой программист, захотелось иметь готовое решение, которое смогло бы переводить любые целые десятичные арабские числа в эквивалентные им римские.
В Википедии нашлась статья с описанием Римской СС, и вскоре я набросал алгоритм перевода из арабских чисел в римские.
Основные числа:
I — 1
V — 5
X — 10
L — 50
C — 100
D — 500
M — 1000
Ноль отсутствует вообще, поэтому будем использовать пустое значение.
Итак, сам алгоритм достаточно прост:
1. Выделяем (если есть) количество целых тысяч. Полученное значение позволить сгенерировать строку с n количеством «M» (читаем, n*1000).
Пример: 2012 после первого пункта даст «MM»
2. Получаем остаток после деления на 1000, чтобы выделить в дальнейшем следующие значения.
3. Выделяем (если возможно), целые 500. При этом учитываем что если полученное значение равно 4 (5+4=9), то следует записывать как значение 1000-100, что в римский СС равнозначно «CM».
Пример: 1887 после этого пункта даст нам «MD».
1945 соответственно «MCM».
4. Получаем остаток от деления на 500.
5. Делим на 100 чтобы выделить целые сотни и складываем к предыдущему результату. Учитываем что если получили 4, что равнозначно 400, то записываем как 500-100, то есть «CD».
Пример: 1709 даст после этого шага «MDCCC».
6. Получаем остаток от деления на 100.
7. Выделяем из него целые пол сотни. Если значение будет равно 4 (то есть 90), то записываем как 100-10, что равно «XC». Иначе прибавляем к строке «L»
Пример: 1986 после всего выдаст нам «MCML».
8. Выделяем остаток от 50.
9. Выделяем целое количество десятков и складываем к строке n раз символ «X». При этом учитываем что 40 пишется как 50-10, то есть «XL».
Пример: 1986 после всего выдаст нам «MCMLXXX».
10. Получаем остаток от деления на 10. Этот шаг отличается от других тем, что можно сразу приравнять остаток к его эквиваленту. 1=I, 7=VII и так далее.
После перебора числа этим алгоритмом мы получаем примерно такое:
2012 == MMXII
Ниже исходник на Java, реализующий алгоритм.
Разрабатывая в основном для платформы J2ME, я всегда старался вносить какие то изюминки в свои проекты. Так, однажды, мне понадобилось выделить пункты меню.
Стандартное решение, через тире или пронумеровав их, использовать не очень хотелось, но другие варианты тогда у меня отсутствовали. Обдумывая как бы лучше оформить эти пункты, я случайно наткнулся на свою старую школьную тетрадку по истории, в которой пункты были пронумерованы с использованием римских цифр. Бинго!
Стоит признаться, на то время моих познаний в римских цифрах хватало только для подсчета до второго-третьего десятка. Что вообще то для нумерации пунктов должно было хватить. Но как любой программист, захотелось иметь готовое решение, которое смогло бы переводить любые целые десятичные арабские числа в эквивалентные им римские.
В Википедии нашлась статья с описанием Римской СС, и вскоре я набросал алгоритм перевода из арабских чисел в римские.
Основные числа:
I — 1
V — 5
X — 10
L — 50
C — 100
D — 500
M — 1000
Ноль отсутствует вообще, поэтому будем использовать пустое значение.
Итак, сам алгоритм достаточно прост:
1. Выделяем (если есть) количество целых тысяч. Полученное значение позволить сгенерировать строку с n количеством «M» (читаем, n*1000).
Пример: 2012 после первого пункта даст «MM»
2. Получаем остаток после деления на 1000, чтобы выделить в дальнейшем следующие значения.
3. Выделяем (если возможно), целые 500. При этом учитываем что если полученное значение равно 4 (5+4=9), то следует записывать как значение 1000-100, что в римский СС равнозначно «CM».
Пример: 1887 после этого пункта даст нам «MD».
1945 соответственно «MCM».
4. Получаем остаток от деления на 500.
5. Делим на 100 чтобы выделить целые сотни и складываем к предыдущему результату. Учитываем что если получили 4, что равнозначно 400, то записываем как 500-100, то есть «CD».
Пример: 1709 даст после этого шага «MDCCC».
6. Получаем остаток от деления на 100.
7. Выделяем из него целые пол сотни. Если значение будет равно 4 (то есть 90), то записываем как 100-10, что равно «XC». Иначе прибавляем к строке «L»
Пример: 1986 после всего выдаст нам «MCML».
8. Выделяем остаток от 50.
9. Выделяем целое количество десятков и складываем к строке n раз символ «X». При этом учитываем что 40 пишется как 50-10, то есть «XL».
Пример: 1986 после всего выдаст нам «MCMLXXX».
10. Получаем остаток от деления на 10. Этот шаг отличается от других тем, что можно сразу приравнять остаток к его эквиваленту. 1=I, 7=VII и так далее.
После перебора числа этим алгоритмом мы получаем примерно такое:
2012 == MMXII
Ниже исходник на Java, реализующий алгоритм.
public class RoManiac { /* Основные числа: I - 1 V - 5 X - 10 L - 50 C - 100 D - 500 M - 1000 Ноль отсутствует вообще,поэтому будем использовать пустое значение */ // Основной метод преобразования из арабских в римские public static String convert(int in) { StringBuffer a = new StringBuffer(""); // Выделяем тысячи int m1 = in / 1000; a.append(M(m1)); // то что осталось после тысяч int m2 = in % 1000; // Выделяем пятьсот из остатка от тысячи int d1 = m2 / 500; a.append(D(d1)); // остаток после выделения полтысячи int d2 = m2 % 500; // Выделяем сотни из остатка int c1 = d2 / 100; a.append(C(c1)); // остаток из сотен int c2 = d2 % 100; // Выделяем полсотни int l1 = c2 / 50; a.append(L(l1)); // остаток int l2 = c2 % 50; // Выделяем десятки int x1 = l2 / 10; a.append(X(x1)); // остаток int x2 = l2 % 10; // Выделяем то что осталось a.append(basic(x2)); return a.toString(); } // преобразовываем целые тысячи // с значениями,кратными десяти, но не 5,всё просто private static String M(int in) { StringBuffer a = new StringBuffer(""); int i = 0; while (i < in) { a.append("M"); i++; } return a.toString(); } // преобразовываем целые сотни private static String C(int in) { if (in == 4) return "CD"; //если 400, то 500-100 else if ((in != 0) && (in < 4)) { StringBuffer a = new StringBuffer(""); int i = 0; while (i < in) { a.append("C"); i++; } return a.toString(); } else return ""; } // целые десятки private static String X(int in) { if (in == 4) return "XL"; // если 40, то 50-10 else if ((in != 0) && (in < 4)) { StringBuffer a = new StringBuffer(""); int i = 0; while (i < in) { a.append("X"); i++; } return a.toString(); } else return ""; } // преобразовываем пол тысячи private static String D(int in) { if (in = 4) return "CM"; // если 900, то 1000-100 else return "D"; } private static String L(int in) { if (in = 4) return "XC"; / / если90 то100 - 10 return "L"; } // От 1 до 9, то что осталось private static String basic(int in) { String[] a = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" }; return a[in]; } } </code> P.S.: Уже в процессе написания подумал что стоить реализовать обратное преобразование.
