Kav*_*a L 54 c# c#-3.0 roman-numerals
我正在尝试编写一个将数字转换为罗马数字的函数.到目前为止这是我的代码; 但是,它仅适用于小于400的数字.是否有一种快速简便的方法来执行此转换,或扩展现有代码以便处理所有情况?在此先感谢您的帮助.
static string convertroman(int number)
{
int l = number / 10;
StringBuilder sb = new StringBuilder();
for (int m = 0; m <= l; m++)
{
if (l == 0)
{
break;
}
if (l == 5)
{
sb = sb.Append(ro.L.ToString());
break;
}
if (l == 4)
{
sb = sb.Append(ro.X.ToString()).Append(ro.L.ToString());
break;
}
if (l == 9)
{
sb = sb.Append(ro.X.ToString()).Append(ro.C.ToString());
break;
}
if (l == 10)
{
sb = sb.Append(ro.C.ToString());
break;
}
if (l > 5 && l < 9)
{
sb = sb.Append(ro.L.ToString());
l = l - 5;
m = 0;
// break;
continue;
}
if (l > 10)
{
sb = sb.Append(ro.C.ToString());
l = l - 10;
m = 0;
// continue;
}
else
{
sb = sb.Append(ro.X.ToString());
}
}
int z = number % 10;
for (int x = 0; x <= z; x++)
{
if (z == 0)
{
break;
}
if (z == 5)
{
sb = sb.Append(ro.V.ToString());
break;
}
if (z == 4)
{
sb = sb.Append(ro.I.ToString()).Append(ro.V.ToString());
break;
}
if (z == 9)
{
sb = sb.Append(ro.I.ToString()).Append(ro.X.ToString());
break;
}
if (z == 10)
{
sb = sb.Append(ro.X.ToString());
break;
}
if (z > 5 && z < 9)
{
sb = sb.Append(ro.V.ToString());
z = z - 5;
x = 0;
}
else
{
sb.Append(ro.I.ToString());
}
}
return sb.ToString();
}
Run Code Online (Sandbox Code Playgroud)
Mos*_*ini 96
试试这个,简单而紧凑:
public static string ToRoman(int number)
{
if ((number < 0) || (number > 3999)) throw new ArgumentOutOfRangeException("insert value betwheen 1 and 3999");
if (number < 1) return string.Empty;
if (number >= 1000) return "M" + ToRoman(number - 1000);
if (number >= 900) return "CM" + ToRoman(number - 900);
if (number >= 500) return "D" + ToRoman(number - 500);
if (number >= 400) return "CD" + ToRoman(number - 400);
if (number >= 100) return "C" + ToRoman(number - 100);
if (number >= 90) return "XC" + ToRoman(number - 90);
if (number >= 50) return "L" + ToRoman(number - 50);
if (number >= 40) return "XL" + ToRoman(number - 40);
if (number >= 10) return "X" + ToRoman(number - 10);
if (number >= 9) return "IX" + ToRoman(number - 9);
if (number >= 5) return "V" + ToRoman(number - 5);
if (number >= 4) return "IV" + ToRoman(number - 4);
if (number >= 1) return "I" + ToRoman(number - 1);
throw new ArgumentOutOfRangeException("something bad happened");
}
Run Code Online (Sandbox Code Playgroud)
jby*_*yrd 21
这是一个更简单的算法 - 请原谅我,我不知道C#所以我用JavaScript写这个,但应该应用相同的算法(我已经评论过,所以你可以理解算法):
function intToRoman(int) {
// create 2-dimensional array, each inner array containing
// roman numeral representations of 1-9 in each respective
// place (ones, tens, hundreds, etc...currently this handles
// integers from 1-3999, but could be easily extended)
var romanNumerals = [
['', 'i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii', 'viii', 'ix'], // ones
['', 'x', 'xx', 'xxx', 'xl', 'l', 'lx', 'lxx', 'lxxx', 'xc'], // tens
['', 'c', 'cc', 'ccc', 'cd', 'd', 'dc', 'dcc', 'dccc', 'cm'], // hundreds
['', 'm', 'mm', 'mmm'] // thousands
];
// split integer string into array and reverse array
var intArr = int.toString().split('').reverse(),
len = intArr.length,
romanNumeral = '',
i = len;
// starting with the highest place (for 3046, it would be the thousands
// place, or 3), get the roman numeral representation for that place
// and append it to the final roman numeral string
while (i--) {
romanNumeral += romanNumerals[ i ][ intArr[i] ];
}
return romanNumeral;
}
console.log( intToRoman(3046) ); // outputs mmmxlvi
Run Code Online (Sandbox Code Playgroud)
Bru*_*oLM 19
我创建了这个类 decimal <=> roman
public static class Roman
{
public static readonly Dictionary<char, int> RomanNumberDictionary;
public static readonly Dictionary<int, string> NumberRomanDictionary;
static Roman()
{
RomanNumberDictionary = new Dictionary<char, int>
{
{ 'I', 1 },
{ 'V', 5 },
{ 'X', 10 },
{ 'L', 50 },
{ 'C', 100 },
{ 'D', 500 },
{ 'M', 1000 },
};
NumberRomanDictionary = new Dictionary<int, string>
{
{ 1000, "M" },
{ 900, "CM" },
{ 500, "D" },
{ 400, "CD" },
{ 100, "C" },
{ 90, "XC" },
{ 50, "L" },
{ 40, "XL" },
{ 10, "X" },
{ 9, "IX" },
{ 5, "V" },
{ 4, "IV" },
{ 1, "I" },
};
}
public static string To(int number)
{
var roman = new StringBuilder();
foreach (var item in NumberRomanDictionary)
{
while (number >= item.Key)
{
roman.Append(item.Value);
number -= item.Key;
}
}
return roman.ToString();
}
public static int From(string roman)
{
int total = 0;
int current, previous = 0;
char currentRoman, previousRoman = '\0';
for (int i = 0; i < roman.Length; i++)
{
currentRoman = roman[i];
previous = previousRoman != '\0' ? RomanNumberDictionary[previousRoman] : '\0';
current = RomanNumberDictionary[currentRoman];
if (previous != 0 && current > previous)
{
total = total - (2 * previous) + current;
}
else
{
total += current;
}
previousRoman = currentRoman;
}
return total;
}
}
Run Code Online (Sandbox Code Playgroud)
一些单元测试To方法:
[TestClass]
public class DecimalToRomanTest
{
[TestMethod]
public void Roman_1_I()
{
Assert.AreEqual("I", Roman.To(1));
}
[TestMethod]
public void Roman_2_II()
{
Assert.AreEqual("II", Roman.To(2));
}
[TestMethod]
public void Roman_3_III()
{
Assert.AreEqual("III", Roman.To(3));
}
[TestMethod]
public void Roman_4_IV()
{
Assert.AreEqual("IV", Roman.To(4));
}
[TestMethod]
public void Roman_5_V()
{
Assert.AreEqual("V", Roman.To(5));
}
[TestMethod]
public void Roman_9_IX()
{
Assert.AreEqual("IX", Roman.To(9));
}
[TestMethod]
public void Roman_10_X()
{
Assert.AreEqual("X", Roman.To(10));
}
[TestMethod]
public void Roman_49_XLIX()
{
Assert.AreEqual("XLIX", Roman.To(49));
}
[TestMethod]
public void Roman_50_L()
{
Assert.AreEqual("L", Roman.To(50));
}
[TestMethod]
public void Roman_100_C()
{
Assert.AreEqual("C", Roman.To(100));
}
[TestMethod]
public void Roman_400_CD()
{
Assert.AreEqual("CD", Roman.To(400));
}
[TestMethod]
public void Roman_500_D()
{
Assert.AreEqual("D", Roman.To(500));
}
[TestMethod]
public void Roman_900_CM()
{
Assert.AreEqual("CM", Roman.To(900));
}
[TestMethod]
public void Roman_1000_M()
{
Assert.AreEqual("M", Roman.To(1000));
}
[TestMethod]
public void Roman_11984_MMMMMMMMMMMCMLXXXIV()
{
Assert.AreEqual("MMMMMMMMMMMCMLXXXIV", Roman.To(11984));
}
}
Run Code Online (Sandbox Code Playgroud)
一些单元测试From方法:
[TestClass]
public class RomanToDecimalTest
{
[TestMethod]
public void Roman_I_1()
{
Assert.AreEqual(1, Roman.From("I"));
}
[TestMethod]
public void Roman_II_2()
{
Assert.AreEqual(2, Roman.From("II"));
}
[TestMethod]
public void Roman_III_3()
{
Assert.AreEqual(3, Roman.From("III"));
}
[TestMethod]
public void Roman_IV_4()
{
Assert.AreEqual(4, Roman.From("IV"));
}
[TestMethod]
public void Roman_V_5()
{
Assert.AreEqual(5, Roman.From("V"));
}
[TestMethod]
public void Roman_IX_9()
{
Assert.AreEqual(9, Roman.From("IX"));
}
[TestMethod]
public void Roman_X_10()
{
Assert.AreEqual(10, Roman.From("X"));
}
[TestMethod]
public void Roman_XLIX_49()
{
Assert.AreEqual(49, Roman.From("XLIX"));
}
[TestMethod]
public void Roman_L_50()
{
Assert.AreEqual(50, Roman.From("L"));
}
[TestMethod]
public void Roman_C_100()
{
Assert.AreEqual(100, Roman.From("C"));
}
[TestMethod]
public void Roman_CD_400()
{
Assert.AreEqual(400, Roman.From("CD"));
}
[TestMethod]
public void Roman_D_500()
{
Assert.AreEqual(500, Roman.From("D"));
}
[TestMethod]
public void Roman_CM_900()
{
Assert.AreEqual(900, Roman.From("CM"));
}
[TestMethod]
public void Roman_M_1000()
{
Assert.AreEqual(1000, Roman.From("M"));
}
[TestMethod]
public void Roman_MMMMMMMMMMMCMLXXXIV_11984()
{
Assert.AreEqual(11984, Roman.From("MMMMMMMMMMMCMLXXXIV"));
}
}
Run Code Online (Sandbox Code Playgroud)
Jam*_*iec 12
这实际上是一个非常有趣的问题,并且基于dofactory.com上的反向示例(将罗马数字转换为小数),它很容易扭转模式,并且可能会稍微改进一下.此代码将支持1到3999999之间的数字.
从上下文类开始,这定义了解析器的I/O.
public class Context
{
private int _input;
private string _output;
public Context(int input)
{
this._input = input;
}
public int Input
{
get { return _input; }
set { _input = value; }
}
public string Output
{
get { return _output; }
set { _output = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
还有一个抽象表达式,它定义了解析操作
public abstract class Expression
{
public abstract void Interpret(Context value);
}
Run Code Online (Sandbox Code Playgroud)
现在,您需要一个抽象终端表达式,它定义将要执行的实际操作:
public abstract class TerminalExpression : Expression
{
public override void Interpret(Context value)
{
while (value.Input - 9 * Multiplier() >= 0)
{
value.Output += Nine();
value.Input -= 9 * Multiplier();
}
while (value.Input - 5 * Multiplier() >= 0)
{
value.Output += Five();
value.Input -= 5 * Multiplier();
}
while (value.Input - 4 * Multiplier() >= 0)
{
value.Output += Four();
value.Input -= 4 * Multiplier();
}
while (value.Input - Multiplier() >= 0)
{
value.Output += One();
value.Input -= Multiplier();
}
}
public abstract string One();
public abstract string Four();
public abstract string Five();
public abstract string Nine();
public abstract int Multiplier();
}
Run Code Online (Sandbox Code Playgroud)
然后,定义罗马数字行为的类(注意,香港专业教育学院使用小写的惯例,其中罗马数字在字母上使用条形来表示1000次)
class MillionExpression : TerminalExpression
{
public override string One() { return "m"; }
public override string Four() { return ""; }
public override string Five() { return ""; }
public override string Nine() { return ""; }
public override int Multiplier() { return 1000000; }
}
class HundredThousandExpression : TerminalExpression
{
public override string One() { return "c"; }
public override string Four() { return "cd"; }
public override string Five() { return "d"; }
public override string Nine() { return "cm"; }
public override int Multiplier() { return 100000; }
}
class ThousandExpression : TerminalExpression
{
public override string One() { return "M"; }
public override string Four() { return "Mv"; }
public override string Five() { return "v"; }
public override string Nine() { return "Mx"; }
public override int Multiplier() { return 1000; }
}
class HundredExpression : TerminalExpression
{
public override string One() { return "C"; }
public override string Four() { return "CD"; }
public override string Five() { return "D"; }
public override string Nine() { return "CM"; }
public override int Multiplier() { return 100; }
}
class TenExpression : TerminalExpression
{
public override string One() { return "X"; }
public override string Four() { return "XL"; }
public override string Five() { return "L"; }
public override string Nine() { return "XC"; }
public override int Multiplier() { return 10; }
}
class OneExpression : TerminalExpression
{
public override string One() { return "I"; }
public override string Four() { return "IV"; }
public override string Five() { return "V"; }
public override string Nine() { return "IX"; }
public override int Multiplier() { return 1; }
}
Run Code Online (Sandbox Code Playgroud)
几乎在那里,我们需要一个包含解析树的非终结表达式:
public class DecimalToRomaNumeralParser : Expression
{
private List<Expression> expressionTree = new List<Expression>()
{
new MillionExpression(),
new HundredThousandExpression(),
new TenThousandExpression(),
new ThousandExpression(),
new HundredExpression(),
new TenExpression(),
new OneExpression()
};
public override void Interpret(Context value)
{
foreach (Expression exp in expressionTree)
{
exp.Interpret(value);
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后,客户端代码:
Context ctx = new Context(123);
var parser = new DecimalToRomaNumeralParser();
parser.Interpret(ctx);
Console.WriteLine(ctx.Output); // Outputs CXXIII
Run Code Online (Sandbox Code Playgroud)
实例:http://rextester.com/rundotnet?code = JJBYW89744
在一行,不是很有效但工作:
public string RomanNumeralFrom(int number)
{
return
new string('I', number)
.Replace(new string('I', 1000), "M")
.Replace(new string('I', 900), "CM")
.Replace(new string('I', 500), "D")
.Replace(new string('I', 400), "CD")
.Replace(new string('I', 100), "C")
.Replace(new string('I', 90), "XC")
.Replace(new string('I', 50), "L")
.Replace(new string('I', 40), "XL")
.Replace(new string('I', 10), "X")
.Replace(new string('I', 9), "IX")
.Replace(new string('I', 5), "V")
.Replace(new string('I', 4), "IV");
}
Run Code Online (Sandbox Code Playgroud)
这应该是最简单的解决方案。
public string IntToRoman(int num)
{
var result = string.Empty;
var map = new Dictionary<string, int>
{
{"M", 1000 },
{"CM", 900},
{"D", 500},
{"CD", 400},
{"C", 100},
{"XC", 90},
{"L", 50},
{"XL", 40},
{"X", 10},
{"IX", 9},
{"V", 5},
{"IV", 4},
{"I", 1}
};
foreach (var pair in map)
{
result += string.Join(string.Empty, Enumerable.Repeat(pair.Key, num / pair.Value));
num %= pair.Value;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
这个版本不像其他版本那样“作弊”:它在内部生成“基本”表,其中包含所有“基本”“可组合”数字。对于懒惰,我使用Tuples,而不是创建专门的类。如果你没有C#4.0中,你可以替换Tuple<>使用KeyValuePair<>,Item1与Key和Item2带Value。
static Tuple<IList<Tuple<string, int>>, int> GenerateBaseNumbers()
{
const string letters = "IVXLCDM";
var tuples = new List<Tuple<string, int>>();
Tuple<string, int> subtractor = null;
int num = 1;
int maxNumber = 0;
for (int i = 0; i < letters.Length; i++)
{
string currentLetter = letters[i].ToString();
if (subtractor != null)
{
tuples.Add(Tuple.Create(subtractor.Item1 + currentLetter, num - subtractor.Item2));
}
tuples.Add(Tuple.Create(currentLetter, num));
bool isEven = i % 2 == 0;
if (isEven)
{
subtractor = tuples[tuples.Count - 1];
}
maxNumber += isEven ? num * 3 : num;
num *= isEven ? 5 : 2;
}
return Tuple.Create((IList<Tuple<string, int>>)new ReadOnlyCollection<Tuple<string, int>>(tuples), maxNumber);
}
static readonly Tuple<IList<Tuple<string, int>>, int> RomanBaseNumbers = GenerateBaseNumbers();
static string FromNumberToRoman(int num)
{
if (num <= 0 || num > RomanBaseNumbers.Item2)
{
throw new ArgumentOutOfRangeException();
}
StringBuilder sb = new StringBuilder();
int i = RomanBaseNumbers.Item1.Count - 1;
while (i >= 0)
{
var current = RomanBaseNumbers.Item1[i];
if (num >= current.Item2)
{
sb.Append(current.Item1);
num -= current.Item2;
}
else
{
i--;
}
}
return sb.ToString();
}
static void Main(string[] args)
{
for (int i = 1; i <= RomanBaseNumbers.Item2; i++)
{
var calc = FromNumberToRoman(i);
Console.WriteLine("{1}", i, calc);
}
}
Run Code Online (Sandbox Code Playgroud)
虽然我喜欢 Mos\xc3\xa8 Bottacini\ 的答案,但在这种情况下使用递归会产生一些负面影响。一是可能的堆栈溢出,因此他限制了数字的上限。虽然,是的,我意识到罗马数字中的巨大数字看起来是多么荒谬,但这仍然是实现结果所不必要的限制。
\n\n此外,由于字符串是不可变的,因此由于大量使用字符串连接,他的版本的内存效率将非常低。下面是我对其方法的修改版本,仅使用 while 循环和 StringBuilder。我的版本实际上应该具有更高的性能(尽管我们正在讨论亚毫秒范围内的差异)并且更容易占用系统内存。
\n\npublic static string ToRomanNumeral(this int value)\n{\n if (value < 0)\n throw new ArgumentOutOfRangeException("Please use a positive integer greater than zero.");\n\n StringBuilder sb = new StringBuilder();\n int remain = value;\n while (remain > 0)\n {\n if (remain >= 1000) { sb.Append("M"); remain -= 1000; }\n else if (remain >= 900) { sb.Append("CM"); remain -= 900; }\n else if (remain >= 500) { sb.Append("D"); remain -= 500; }\n else if (remain >= 400) { sb.Append("CD"); remain -= 400; }\n else if (remain >= 100) { sb.Append("C"); remain -= 100; }\n else if (remain >= 90) { sb.Append("XC"); remain -= 90; }\n else if (remain >= 50) { sb.Append("L"); remain -= 50; }\n else if (remain >= 40) { sb.Append("XL"); remain -= 40; }\n else if (remain >= 10) { sb.Append("X"); remain -= 10; }\n else if (remain >= 9) { sb.Append("IX"); remain -= 9; }\n else if (remain >= 5) { sb.Append("V"); remain -= 5; }\n else if (remain >= 4) { sb.Append("IV"); remain -= 4; }\n else if (remain >= 1) { sb.Append("I"); remain -= 1; }\n else throw new Exception("Unexpected error."); // <<-- shouldn\'t be possble to get here, but it ensures that we will never have an infinite loop (in case the computer is on crack that day).\n }\n\n return sb.ToString();\n}\nRun Code Online (Sandbox Code Playgroud)\n
这是DotNetSnippets 的一个超薄解决方案
private string ToRomanNumber(int number)
{
StringBuilder result = new StringBuilder();
int[] digitsValues = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 };
string[] romanDigits = { "I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M" };
while (number > 0)
{
for (int i = digitsValues.Count() - 1; i >= 0; i--)
if (number / digitsValues[i] >= 1)
{
number -= digitsValues[i];
result.Append(romanDigits[i]);
break;
}
}
return result.ToString();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
63648 次 |
| 最近记录: |