C语言 如何将整数值转换为罗马数字字符串?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4986521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert integer value to Roman numeral string?
提问by mr_eclair
How can I convert an integer to its String representation in Roman numerals in C ?
如何将整数转换为 C 中罗马数字的字符串表示形式?
回答by paxdiablo
The easiest way is probably to set up three arrays for the complex cases and use a simple function like:
最简单的方法可能是为复杂情况设置三个数组并使用一个简单的函数,例如:
// 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 = '// 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 = '/* 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] = '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;
}
}
}
';
return k;
}
/* gcc -Wall -ansi roman.c */
int main (int argc, char **argv)
{
char buf[1024] = {' static string ConvertToRoman(int num)
{
int d = 0;
string result = "";
while (num > 0)
{
int n = num % 10;
result = DigitToRoman(n, d) + result;
d++;
num = num / 10;
}
return result;
}
static string DigitToRoman(int n, int d)
{
string[,] map = new string[3, 3] { { "I", "V", "X" }, { "X", "L", "C" }, { "C", "D", "M" } };
string result="";
if (d <= 2)
{
switch (n)
{
case 0:
result = "";
break;
case 1:
result = map[d, 0];
break;
case 2:
result = map[d, 0] + map[d, 0];
break;
case 3:
result = map[d, 0] + map[d, 0] + map[d, 0];
break;
case 4:
result = map[d, 0] + map[d, 1];
break;
case 5:
result = map[d, 1];
break;
case 6:
result = map[d, 1] + map[d, 0];
break;
case 7:
result = map[d, 1] + map[d, 0] + map[d, 0];
break;
case 8:
result = map[d, 1] + map[d, 0] + map[d, 0] + map[d, 0];
break;
case 9:
result = map[d, 0] + map[d, 2];
break;
}
}
else if (d == 3 && n < 5)
{
while (--n >= 0)
{
result += "M";
}
}
else
{
return "Error! Can't convert numbers larger than 4999.";
}
return result;
}
'};
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;
}
';
return 1;
}
';
}
This will handle any unsigned integer although large numbers will have an awful lot of Mcharacters at the front and the caller has to ensure their buffer is large enough.
这将处理任何无符号整数,尽管大数字M前面会有大量字符,并且调用者必须确保它们的缓冲区足够大。
Once the number has been reduced below 1000, it's a simple 3-table lookup, one each for the hundreds, tens and units. For example, take the case where valis 314.
一旦数量减少到 1000 以下,它就是一个简单的 3 表查找,每个表查找百、十和单位。例如,以valis为例314。
val/100will be 3in that case so the hunsarray lookup will give CCC, then val = val % 100gives you 14for the tenslookup.
val/100将3在这种情况下,因此huns数组查找将给出CCC,然后val = val % 100为您14提供tens查找。
Then val/10will be 1in that case so the tensarray lookup will give X, then val = val % 10gives you 4for the oneslookup.
然后val/10将1在这种情况下,因此tens数组查找将给出X,然后val = val % 10为您4提供ones查找。
Then valwill be 4in that case so the onesarray lookup will give IV.
然后val将4在这种情况下,因此ones数组查找将给出IV.
That gives you CCCXIVfor 314.
这给了你CCCXIVfor 314.
A buffer-overflow-checking version is a simple step up from there:
缓冲区溢出检查版本是一个简单的步骤:
##代码##although, at that point, you could think of refactoring the processing of hundreds, tens and units into a separate function since they're so similar. I'll leave that as an extra exercise.
不过,在那时,您可以考虑将数百、十和单位的处理重构为一个单独的函数,因为它们非常相似。我将把它作为额外的练习。
回答by j. andrew shusta
don't use a sissy pre-calculated map for the difficult cases.
不要在困难的情况下使用娘娘腔预先计算好的地图。
##代码##you don't actually need to declare Seither. it should be easy to see why.
您实际上也不需要声明S。应该很容易看出原因。
回答by Oliver
I think ValueConverteris one of the most elegant methods to convert an integer into a Roman numeral. I hope Dante isn't too angry about that I post his code here:
我认为ValueConverter是将整数转换为罗马数字的最优雅的方法之一。我希望但丁不要因为我在这里发布他的代码而生气:
##代码##
