как преобразовать целочисленное значение в римскую цифровую строку?

<p>как я могу преобразовать целое число в его строковое представление римскими цифрами в c?</p>

<p>возможно, самый простой способ - создать три массива для сложных случаев и использовать простую функцию, например:</p><pre><code>// converttoroman: // in: val: value to convert. // res: buffer to hold result. // out: n/a // cav: caller responsible for buffer size. void converttoroman (unsigned int val, char *res) { char *huns[] = {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"}; char *tens[] = {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"}; char *ones[] = {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"}; int size[] = { 0, 1, 2, 3, 2, 1, 2, 3, 4, 2}; // add 'm' until we drop below 1000. while (val >= 1000) { *res++ = 'm'; val -= 1000; } // add each of the correct elements, adjusting as we go. strcpy (res, huns[val/100]); res += size[val/100]; val = val % 100; strcpy (res, tens[val/10]); res += size[val/10]; val = val % 10; strcpy (res, ones[val]); res += size[val]; // finish string off. *res = '\0'; } </code></pre><p>это будет обрабатывать любое целое число без знака, хотя большие числа будут иметь очень много символов <code>m</code> спереди, и вызывающий должен убедиться, что их буфер достаточно велик.</p><p>как только число было уменьшено ниже 1000, это простой поиск по 3 таблицам, по одному на сотни, десятки и единицы. например, возьмем случай, когда <code>val</code> равен <code>314</code>.</p><p>в этом случае <code>val/100</code> будет <code>3</code>, поэтому поиск в массиве <code>huns</code> даст <code>ccc</code>, тогда <code>val = val % 100</code> даст вам <code>14</code> для поиска <code>tens</code>.</p><p>тогда <code>val/10</code> будет <code>1</code> в этом случае, поэтому поиск массива <code>tens</code> даст <code>x</code>, тогда <code>val = val % 10</code> даст вам <code>4</code> для поиска <code>ones</code>.</p><p>тогда <code>val</code> будет <code>4</code> в этом случае, поэтому поиск массива <code>ones</code> даст <code>iv</code>.</p><p>это дает вам <code>cccxiv</code> для <code>314</code>.</p><hr><p>версия с проверкой переполнения буфера является простым шагом оттуда:</p><pre><code>// converttoroman: // in: val: value to convert. // res: buffer to hold result. // out: returns 0 if not enough space, else 1. // cav: n/a int converttoroman (unsigned int val, char *res, size\_t sz) { char *huns[] = {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"}; char *tens[] = {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"}; char *ones[] = {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"}; int size[] = { 0, 1, 2, 3, 2, 1, 2, 3, 4, 2}; // add 'm' until we drop below 1000. while (val >= 1000) { if (sz-- < 1) return 0; *res++ = 'm'; val -= 1000; } // add each of the correct elements, adjusting as we go. if (sz < size[val/100]) return 0; sz -= size[val/100]; strcpy (res, huns[val/100]); res += size[val/100]; val = val % 100; if (sz < size[val/10]) return 0; sz -= size[val/10]; strcpy (res, tens[val/10]); res += size[val/10]; val = val % 10; if (sz < size[val) return 0; sz -= size[val]; strcpy (res, ones[val]); res += size[val]; // finish string off. if (sz < 1) return 0; *res = '\0'; return 1; } </code></pre><p>хотя в этот момент вы могли бы подумать о том, чтобы реорганизовать обработку сотен, десятков и единиц в отдельную функцию, поскольку они очень похожи. я оставлю это как дополнительное упражнение.</p>

<p>не используйте заранее рассчитанную карту для сложных случаев.</p><pre><code>/* roman.c */ #include <stdio.h> /* lh(1) roman numeral conversion */ int rn\_lh1 (char *buf, const size\_t maxlen, int n) { int s[] = { 0, 2, 4, 2, 4, 2, 4 }; int d[] = { 1000, 500, 100, 50, 10, 5, 1 }; char c[] = { 'm', 'd', 'c', 'l', 'x', 'v', 'i' }; const size\_t l = sizeof(d) / sizeof(int) - 1; size\_t k = 0; /* index into output buffer */ int i = 0; /* index into maps */ int r, r2; while (n > 0) { if (d[i] <= n) { r = n / d[i]; n = n - (r * d[i]); /* lookahead */ r2 = n / d[i+1]; if (i < l && r2 >= s[i+1]) { /* will violate repeat boundary on next pass */ n = n - (r2 * d[i+1]); if (k < maxlen) buf[k++] = c[i+1]; if (k < maxlen) buf[k++] = c[i-1]; } else if (s[i] && r >= s[i]) { /* violated repeat boundary on this pass */ if (k < maxlen) buf[k++] = c[i]; if (k < maxlen) buf[k++] = c[i-1]; } else while (r-- > 0 && k < maxlen) buf[k++] = c[i]; } i++; } if (k < maxlen) buf[k] = '\0'; return k; } /* gcc -wall -ansi roman.c */ int main (int argc, char **argv) { char buf[1024] = {'\0'}; size\_t len; int k; for (k = 1991; k < 2047; k++) { len = rn\_lh1(buf, 1023, k); printf("%3lu % 4d %s\n", len, k, buf); } return 0; } </code></pre><p>вам на самом деле не нужно объявлять <code>s</code> либо. должно быть легко понять почему.</p>

<pre><code>#ifndef numberof #define numberof(a) ((int)(sizeof(a)/sizeof((a)[0]))) #endif static void roman(char *out, int max, int number) { static int romani[] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 }; static const char *romana[] = { "m", "cm", "d", "cd", "c", "xc", "l", "xl", "x", "ix", "v", "iv", "i" }; int i, v; out[0] = 0; for (i = 0; i < numberof(romani); i++) { if (number <= 0) break; v = romani[i]; while (number >= v) { strcat\_s(out, max, romana[i]); number -= v; } } } </code></pre>

<p>я думаю <a href="http://blogs.msdn.com/b/danteg/archive/2006/03/22/558450.aspx">valueconverter</a> это один из самых элегантных методов для преобразования целого числа в римскую цифру. я надеюсь, что данте не слишком зол на то, что я разместил его код здесь:</p><pre><code>public class romannumeralizer : ivalueconverter { private static ilist<romannumeralpair> \_pairs; static romannumeralizer() { var list = new list<romannumeralpair>(); list.add(new romannumeralpair(1000, "m")); list.add(new romannumeralpair(900, "cm")); list.add(new romannumeralpair(500, "d")); list.add(new romannumeralpair(400, "cd")); list.add(new romannumeralpair(100, "c")); list.add(new romannumeralpair(90, "xc")); list.add(new romannumeralpair(50, "l")); list.add(new romannumeralpair(40, "xl")); list.add(new romannumeralpair(10, "x")); list.add(new romannumeralpair(9, "ix")); list.add(new romannumeralpair(5, "v")); list.add(new romannumeralpair(4, "iv")); list.add(new romannumeralpair(1, "i")); \_pairs = list.asreadonly(); } private ilist<romannumeralpair> pairset { get { return \_pairs; } } public object convert(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { return converttoromannumeral(system.convert.toint32(value)); } public object convertback(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { return null; } private string converttoromannumeral(int input) { stringbuilder mybuilder = new stringbuilder(); foreach (romannumeralpair thispair in \_pairs) { while (input >= thispair.value) { mybuilder.append(thispair.romanvalue); input -= thispair.value; } } return mybuilder.tostring(); } } public class romannumeralpair { private string \_romanvalue; private int \_value; public romannumeralpair(int value, string stringvalue) { this.\_value = value; this.\_romanvalue = stringvalue; } public string romanvalue { get { return this.\_romanvalue; } } public int value { get { return this.\_value; } } } </code></pre>