Доброе время суток, Хабраюзер.
Разрабатывая в основном для платформы 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.: Уже в процессе написания подумал что стоить реализовать обратное преобразование.