C# 罗马数字到整数
我有一个产品的转让,不幸的是必须得到产品名称匹配。这里最大的问题是我可能会因为罗马数字而得到重复的产品。有时同一产品会以罗马数字命名,有时则是常规数字 这些产品是移动设备。示例-三星Galaxy SII-三星Galaxy S2C# 罗马数字到整数,c#,roman-numerals,C#,Roman Numerals,我有一个产品的转让,不幸的是必须得到产品名称匹配。这里最大的问题是我可能会因为罗马数字而得到重复的产品。有时同一产品会以罗马数字命名,有时则是常规数字 这些产品是移动设备。示例-三星Galaxy SII-三星Galaxy S2 人们怎么能编写这样的函数呢?我刚刚编写了一个简单的罗马数字转换器,但它并没有进行大量的错误检查,但它似乎适用于所有我能够正确格式化的东西 public static int ConvertRomanNumtoInt(string strRomanValue) {
人们怎么能编写这样的函数呢?我刚刚编写了一个简单的罗马数字转换器,但它并没有进行大量的错误检查,但它似乎适用于所有我能够正确格式化的东西
public static int ConvertRomanNumtoInt(string strRomanValue)
{
Dictionary RomanNumbers = new Dictionary
{
{"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}
};
int retVal = 0;
foreach (KeyValuePair pair in RomanNumbers)
{
while (strRomanValue.IndexOf(pair.Key.ToString()) == 0)
{
retVal += int.Parse(pair.Value.ToString());
strRomanValue = strRomanValue.Substring(pair.Key.ToString().Length);
}
}
return retVal;
}
public class RomanNumber
{
public string Numeral { get; set; }
public int Value { get; set; }
public int Hierarchy { get; set; }
}
public List<RomanNumber> RomanNumbers = new List<RomanNumber>
{
new RomanNumber {Numeral = "M", Value = 1000, Hierarchy = 4},
//{"CM", 900},
new RomanNumber {Numeral = "D", Value = 500, Hierarchy = 4},
//{"CD", 400},
new RomanNumber {Numeral = "C", Value = 100, Hierarchy = 3},
//{"XC", 90},
new RomanNumber {Numeral = "L", Value = 50, Hierarchy = 3},
//{"XL", 40},
new RomanNumber {Numeral = "X", Value = 10, Hierarchy = 2},
//{"IX", 9},
new RomanNumber {Numeral = "V", Value = 5, Hierarchy = 2},
//{"IV", 4},
new RomanNumber {Numeral = "I", Value = 1, Hierarchy = 1}
};
/// <summary>
/// Converts the roman numeral to int, assumption roman numeral is properly formatted.
/// </summary>
/// <param name="romanNumeralString">The roman numeral string.</param>
/// <returns></returns>
private int ConvertRomanNumeralToInt(string romanNumeralString)
{
if (romanNumeralString == null) return int.MinValue;
var total = 0;
for (var i = 0; i < romanNumeralString.Length; i++)
{
// get current value
var current = romanNumeralString[i].ToString();
var curRomanNum = RomanNumbers.First(rn => rn.Numeral.ToUpper() == current.ToUpper());
// last number just add the value and exit
if (i + 1 == romanNumeralString.Length)
{
total += curRomanNum.Value;
break;
}
// check for exceptions IV, IX, XL, XC etc
var next = romanNumeralString[i + 1].ToString();
var nextRomanNum = RomanNumbers.First(rn => rn.Numeral.ToUpper() == next.ToUpper());
// exception found
if (curRomanNum.Hierarchy == (nextRomanNum.Hierarchy - 1))
{
total += nextRomanNum.Value - curRomanNum.Value;
i++;
}
else
{
total += curRomanNum.Value;
}
}
return total;
}
公共类编号
{
公共字符串数字{get;set;}
公共int值{get;set;}
公共整数层次结构{get;set;}
}
公共列表编号=新列表
{
新数字{numeric=“M”,值=1000,层次结构=4},
//{“CM”,900},
新数字{numeric=“D”,值=500,层次结构=4},
//{“CD”,400},
新数字{numeric=“C”,值=100,层次结构=3},
//{“XC”,90},
新数字{numeric=“L”,值=50,层次结构=3},
//{“XL”,40},
新数字{numeric=“X”,值=10,层次结构=2},
//{“IX”,9},
新罗马数字{numeric=“V”,值=5,层次结构=2},
//{“IV”,4},
新罗马数字{numeric=“I”,值=1,层次结构=1}
};
///
///将罗马数字转换为int,假设罗马数字格式正确。
///
///罗马数字串。
///
private int convertRomanDigitalToInt(字符串RomanDigitalString)
{
if(RomanDigitalString==null)返回int.MinValue;
var合计=0;
for(变量i=0;irn.numeric.ToUpper()==current.ToUpper());
//最后一个数字只需添加值并退出即可
if(i+1==RomanDigitalString.Length)
{
总计+=货币年值;
打破
}
//检查例外情况IV、IX、XL、XC等
var next=RomanNumeratorString[i+1].ToString();
var nextRomanNum=romanumbers.First(rn=>rn.numeric.ToUpper()==next.ToUpper());
//发现异常
if(curRomanNum.Hierarchy==(nextRomanNum.Hierarchy-1))
{
总计+=下一个季度价值-当前年度价值;
i++;
}
其他的
{
总计+=货币年值;
}
}
返回总数;
}
我将通过在.net中使用数组来建议一种最简单的方法:注释在C#部分中给出,以供解释
VB.net
Public Class Form1
Dim indx() As Integer = {1, 2, 3, 4, 5, 10, 50, 100, 500, 1000}
Dim row() As String = {"I", "II", "III", "IV", "V", "X", "L", "C", "D", "M"}
Dim limit As Integer = 9
Dim output As String = ""
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim num As Integer
output = ""
num = CInt(txt1.Text)
While num > 0
num = find(num)
End While
txt2.Text = output
End Sub
Public Function find(ByVal Num As Integer) As Integer
Dim i As Integer = 0
While indx(i) <= Num
i += 1
End While
If i <> 0 Then
limit = i - 1
Else
limit = 0
End If
output = output & row(limit)
Num = Num - indx(limit)
Return Num
End Function
End Class
公共类表单1
Dim indx()作为整数={1,2,3,4,5,10,501005001000}
Dim row()作为字符串={“I”、“II”、“III”、“IV”、“V”、“X”、“L”、“C”、“D”、“M”}
尺寸限制为整数=9
将输出变暗为字符串=“”
私有子按钮1\u单击(ByVal sender作为System.Object,ByVal e作为System.EventArgs)处理按钮1。单击
Dim num作为整数
output=“”
num=CInt(txt1.Text)
而num>0
num=查找(num)
结束时
txt2.Text=输出
端接头
公共函数find(ByVal Num作为整数)作为整数
尺寸i为整数=0
而indx(i)0){
num=查找(num);
//调用函数进行处理
}
txt2.Text=输出;
//在text2中显示输出
}
公共整数查找(整数)
{
int i=0;
//循环变量已初始化为0
//循环,直到indx(i).值大于或等于num
虽然(indx(i)我注意到这里有一些非常复杂的解决方案,但这是一个非常简单的问题。我制定了一个解决方案,避免了硬编码“异常”(IV、IX、XL等).我使用for
循环查看罗马数字字符串中的下一个字符,以查看与数字相关的数字是否应减去或添加到总数中。为简单起见,我假设所有输入都有效
private static Dictionary<char, int> RomanMap = new Dictionary<char, int>()
{
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000}
};
public static int RomanToInteger(string roman)
{
int number = 0;
for (int i = 0; i < roman.Length; i++)
{
if (i + 1 < roman.Length && RomanMap[roman[i]] < RomanMap[roman[i + 1]])
{
number -= RomanMap[roman[i]];
}
else
{
number += RomanMap[roman[i]];
}
}
return number;
}
更简单易读的C#实现:
- 将I映射到1,V映射到5,X映射到10,L映射到50,C映射到100,D映射到500,M映射到1000
- 使用一个foreach循环(foreach故意使用,带有以前的值
等一下)
- 将映射的数字添加到总数中
- 如果在V或X之前加上I,在L或C之前加上X,在D或M之前加上C,则减去之前加上的数字的两倍(此处不允许所有字符!)
- 返回空字符串上的0(不用于罗马数字),字母错误
或不允许用于减法的字符
- 备注:它还没有完全完成,我们没有检查所有可能的条件以获得有效的输入字符串
代码:
private static Dictionary\u romanMap=新字典
{
{'I',1},{'V',5},{'X',10},{'L',50},{'C',100},{'D',500},{'M',1000}
};
公共静态int-convertRomantonNumber(字符串文本)
{
int totalValue=0,prevValue=0;
foreach(文本中的var c)
{
如果(!_romanMap.ContainsKey(c))
返回0;
var crtValue=_romanMap[c];
totalValue+=crtValue;
if(prevValue!=0&&prevValue
我是这么说的。你可以把罗马数字倒过来,这样比较起来就容易多了。
公共静态int-pairConversion(int-dec、int-lastNum、int-lastDec)
{
如果(lastNum>dec)
返回
private static Dictionary<char, int> RomanMap = new Dictionary<char, int>()
{
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000}
};
public static int RomanToInteger(string roman)
{
int number = 0;
for (int i = 0; i < roman.Length; i++)
{
if (i + 1 < roman.Length && RomanMap[roman[i]] < RomanMap[roman[i + 1]])
{
number -= RomanMap[roman[i]];
}
else
{
number += RomanMap[roman[i]];
}
}
return number;
}
public static int RomanToInteger(string roman)
{
int number = 0;
char previousChar = roman[0];
foreach(char currentChar in roman)
{
number += RomanMap[currentChar];
if(RomanMap[previousChar] < RomanMap[currentChar])
{
number -= RomanMap[previousChar] * 2;
}
previousChar = currentChar;
}
return number;
}
private static Dictionary<char, int> _romanMap = new Dictionary<char, int>
{
{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000}
};
public static int ConvertRomanToNumber(string text)
{
int totalValue = 0, prevValue = 0;
foreach (var c in text)
{
if (!_romanMap.ContainsKey(c))
return 0;
var crtValue = _romanMap[c];
totalValue += crtValue;
if (prevValue != 0 && prevValue < crtValue)
{
if (prevValue == 1 && (crtValue == 5 || crtValue == 10)
|| prevValue == 10 && (crtValue == 50 || crtValue == 100)
|| prevValue == 100 && (crtValue == 500 || crtValue == 1000))
totalValue -= 2 * prevValue;
else
return 0;
}
prevValue = crtValue;
}
return totalValue;
}
public static int ConvertRomanNumtoInt(string strRomanValue)
{
var dec = 0;
var lastNum = 0;
foreach (var c in strRomanValue.Reverse())
{
switch (c)
{
case 'I':
dec = pairConversion(1, lastNum, dec);
lastNum = 1;
break;
case 'V':
dec=pairConversion(5,lastNum, dec);
lastNum = 5;
break;
case 'X':
dec = pairConversion(10, lastNum, dec);
lastNum = 10;
break;
case 'L':
dec = pairConversion(50, lastNum, dec);
lastNum = 50;
break;
case 'C':
dec = pairConversion(100, lastNum, dec);
lastNum = 100;
break;
case 'D':
dec = pairConversion(500, lastNum, dec);
lastNum = 500;
break;
case 'M':
dec = pairConversion(1000, lastNum, dec);
lastNum = 1000;
break;
}
}
return dec;
}
public static IDictionary<char, int> CharValues
{
get
{
return new Dictionary<char, int>
{{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000}};
}
}
public static int RomanNumeralToInteger(IEnumerable<char> romanNumerals)
{
int retVal = 0;
//go backwards
for (int i = romanNumerals.Count() - 1; i >= 0; i--)
{
//get current character
char c = romanNumerals.ElementAt(i);
//error checking
if (!CharValues.ContainsKey(c)) throw new InvalidRomanNumeralCharacterException(c);
//determine if we are adding or subtracting
bool op = romanNumerals.Skip(i).Any(rn => CharValues[rn] > CharValues[c]);
//then do so
retVal = op ? retVal - CharValues[c] : retVal + CharValues[c];
}
return retVal;
}
public int RomanToInt(string s)
{
var dict = new Dictionary<char, int>();
dict['I'] = 1;
dict['V'] = 5;
dict['X'] = 10;
dict['L'] = 50;
dict['C'] = 100;
dict['D'] = 500;
dict['M'] = 1000;
Stack<char> st = new Stack<char>();
foreach (char ch in s.ToCharArray())
st.Push(ch);
int result = 0;
while (st.Count > 0)
{
var c1=st.Pop();
var ch1 = dict[c1];
if (st.Count > 0)
{
var c2 = st.Peek();
var ch2 = dict[c2];
if (ch2 < ch1)
{
result += (ch1 - ch2);
st.Pop();
}
else
{
result += ch1;
}
}
else
{
result += ch1;
}
}
return result;
}
public static class RomanNumber {
static string[] units = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
static string[] tens = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
static string[] hundreds = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
static string[] thousands = { "", "M", "MM", "MMM" };
static public bool IsRomanNumber(string source) {
try {
return RomanNumberToInt(source) > 0;
}
catch {
return false;
}
}
/// <summary>
/// Parses a string containing a roman number.
/// </summary>
/// <param name="source">source string</param>
/// <returns>The integer value of the parsed roman numeral</returns>
/// <remarks>
/// Throws an exception on invalid source.
/// Throws an exception if source is not a valid roman number.
/// Supports roman numbers from "I" to "MMMCMXCIX" ( 1 to 3999 )
/// NOTE : "IMMM" is not valid</remarks>
public static int RomanNumberToInt(string source) {
if (String.IsNullOrWhiteSpace(source)) {
throw new ArgumentNullException();
}
int total = 0;
string buffer = source;
// parse the last four characters in the string
// each time we check the buffer against a number array,
// starting from units up to thousands
// we quit as soon as there are no remaing characters to parse
total += RipOff(buffer, units, out buffer);
if (buffer != null) {
total += (RipOff(buffer, tens, out buffer)) * 10;
}
if (buffer != null) {
total += (RipOff(buffer, hundreds, out buffer)) * 100;
}
if (buffer != null) {
total += (RipOff(buffer, thousands, out buffer)) * 1000;
}
// after parsing for thousands, if there is any character left, this is not a valid roman number
if (buffer != null) {
throw new ArgumentException(String.Format("{0} is not a valid roman number", buffer));
}
return total;
}
/// <summary>
/// Given a string, takes the four characters on the right,
/// search an element in the numbers array and returns the remaing characters.
/// </summary>
/// <param name="source">source string to parse</param>
/// <param name="numbers">array of roman numerals</param>
/// <param name="left">remaining characters on the left</param>
/// <returns>If it finds a roman numeral returns its integer value; otherwise returns zero</returns>
public static int RipOff(string source, string[] numbers, out string left) {
int result = 0;
string buffer = null;
// we take the last four characters : this is the length of the longest numeral in our arrays
// ("VIII", "LXXX", "DCCC")
// or all if source length is 4 or less
if (source.Length > 4) {
buffer = source.Substring(source.Length - 4);
left = source.Substring(0, source.Length - 4);
}
else {
buffer = source;
left = null;
}
// see if buffer exists in the numbers array
// if it does not, skip the first character and try again
// until buffer contains only one character
// append the skipped character to the left arguments
while (!numbers.Contains(buffer)) {
if (buffer.Length == 1) {
left = source; // failed
break;
}
else {
left += buffer.Substring(0, 1);
buffer = buffer.Substring(1);
}
}
if (buffer.Length > 0) {
if (numbers.Contains(buffer)) {
result = Array.IndexOf(numbers, buffer);
}
}
return result;
}
}
}
/// <summary>
/// Converts a Roman number string into a Arabic number
/// </summary>
/// <param name="romanNumber">the Roman number string</param>
/// <returns>the Arabic number (0 if the given string is not convertible to a Roman number)</returns>
public static int ToArabicNumber(string romanNumber)
{
string[] replaceRom = { "CM", "CD", "XC", "XL", "IX", "IV" };
string[] replaceNum = { "DCCCC", "CCCC", "LXXXX", "XXXX", "VIIII", "IIII" };
string[] roman = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
int[] arabic = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
return Enumerable.Range(0, replaceRom.Length)
.Aggregate
(
romanNumber,
(agg, cur) => agg.Replace(replaceRom[cur], replaceNum[cur]),
agg => agg.ToArray()
)
.Aggregate
(
0,
(agg, cur) =>
{
int idx = Array.IndexOf(roman, cur.ToString());
return idx < 0 ? 0 : agg + arabic[idx];
},
agg => agg
);
}
/// <summary>
/// Converts a Arabic number into a Roman number string
/// </summary>
/// <param name="arabicNumber">the Arabic number</param>
/// <returns>the Roman number string</returns>
public static string ToRomanNumber(int arabicNumber)
{
string[] roman = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
int[] arabic = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
return Enumerable.Range(0, arabic.Length)
.Aggregate
(
Tuple.Create(arabicNumber, string.Empty),
(agg, cur) =>
{
int remainder = agg.Item1 % arabic[cur];
string concat = agg.Item2 + string.Concat(Enumerable.Range(0, agg.Item1 / arabic[cur]).Select(num => roman[cur]));
return Tuple.Create(remainder, concat);
},
agg => agg.Item2
);
}
public int SimplerConverter(string number)
{
number = number.ToUpper();
var result = 0;
foreach (var letter in number)
{
result += ConvertLetterToNumber(letter);
}
if (number.Contains("IV")|| number.Contains("IX"))
result -= 2;
if (number.Contains("XL")|| number.Contains("XC"))
result -= 20;
if (number.Contains("CD")|| number.Contains("CM"))
result -= 200;
return result;
}
private int ConvertLetterToNumber(char letter)
{
switch (letter)
{
case 'M':
{
return 1000;
}
case 'D':
{
return 500;
}
case 'C':
{
return 100;
}
case 'L':
{
return 50;
}
case 'X':
{
return 10;
}
case 'V':
{
return 5;
}
case 'I':
{
return 1;
}
default:
{
throw new ArgumentException("Ivalid charakter");
}
}
}
ii X iiv # Pick the greatest value in the literal `iixiiv` (symbolized by uppercase)
(iiv) + x - (ii) # Subtract the lefthand-side, add the righthand-side
(V - (ii)) + x - ((I) + i) # Pick the greatest values, again
(v - ((I) + i)) + x - ((i) + i) # Pick the greatest value of the last numeral compound
(5 - ((1) + 1)) + 10 - ((1) + 1)
(5 - (2)) + 10 - (2)
3 + 10 - 2
= 11
public class RomanNumerals
{
private List<Tuple<char, ushort, char?[]>> _validNumerals = new List<Tuple<char, ushort, char?[]>>()
{
new Tuple<char, ushort, char?[]>('I', 1, new char? [] {'V', 'X'}),
new Tuple<char, ushort, char?[]>('V', 5, null),
new Tuple<char, ushort, char?[]>('X', 10, new char?[] {'L', 'C'}),
new Tuple<char, ushort, char?[]>('L', 50, null),
new Tuple<char, ushort, char?[]>('C', 100, new char? [] {'D', 'M'}),
new Tuple<char, ushort, char?[]>('D', 500, null),
new Tuple<char, ushort, char?[]>('M', 1000, new char? [] {null, null})
};
public int TranslateRomanNumeral(string input)
{
var inputList = input?.ToUpper().ToList();
if (inputList == null || inputList.Any(x => _validNumerals.Select(t => t.Item1).Contains(x) == false))
{
throw new ArgumentException();
}
char? valForSubtraction = null;
int result = 0;
bool noAdding = false;
int equalSum = 0;
for (int i = 0; i < inputList.Count; i++)
{
var currentNumeral = _validNumerals.FirstOrDefault(s => s.Item1 == inputList[i]);
var nextNumeral = i < inputList.Count - 1 ? _validNumerals.FirstOrDefault(s => s.Item1 == inputList[i + 1]) : null;
bool currentIsDecimalPower = currentNumeral?.Item3?.Any() ?? false;
if (nextNumeral != null)
{
// Syntax and Semantics checks
if ((currentNumeral.Item2 < nextNumeral.Item2) && (currentIsDecimalPower == false || currentNumeral.Item3.Any(s => s == nextNumeral.Item1) == false) ||
(currentNumeral.Item2 == nextNumeral.Item2) && (currentIsDecimalPower == false || nextNumeral.Item1 == valForSubtraction) ||
(currentIsDecimalPower && result > 0 && ((nextNumeral.Item2 -currentNumeral.Item2) > result )) ||
(currentNumeral.Item2 > nextNumeral.Item2) && (nextNumeral.Item1 == valForSubtraction)
)
{
throw new ArgumentException();
}
if (currentNumeral.Item2 == nextNumeral.Item2)
{
equalSum += equalSum == 0 ? currentNumeral.Item2 + nextNumeral.Item2 : nextNumeral.Item2;
int? smallest = null;
var list = _validNumerals.Where(p => _validNumerals.FirstOrDefault(s => s.Item1 == currentNumeral.Item1).Item3.Any(s2 => s2 != null && s2 == p.Item1)).ToList();
if (list.Any())
{
smallest = list.Select(s3 => s3.Item2).ToList().Min();
}
// Another Semantics check
if (currentNumeral.Item3 != null && equalSum >= (smallest - currentNumeral.Item2))
{
throw new ArgumentException();
}
result += noAdding ? 0 : currentNumeral.Item2 + nextNumeral.Item2;
noAdding = !noAdding;
valForSubtraction = null;
}
else
if (currentNumeral.Item2 < nextNumeral.Item2)
{
equalSum = 0;
result += nextNumeral.Item2 - currentNumeral.Item2;
valForSubtraction = currentNumeral.Item1;
noAdding = true;
}
else
if (currentNumeral.Item2 > nextNumeral.Item2)
{
equalSum = 0;
result += noAdding ? 0 : currentNumeral.Item2;
noAdding = false;
valForSubtraction = null;
}
}
else
{
result += noAdding ? 0 : currentNumeral.Item2;
}
}
return result;
}
}
[TestFixture]
public class RomanNumeralsTests
{
[Test]
public void TranslateRomanNumeral_WhenArgumentIsNull_RaiseArgumentNullException()
{
var romanNumerals = new RomanNumerals();
Assert.Throws<ArgumentException>(() => romanNumerals.TranslateRomanNumeral(null));
}
[TestCase("A")]
[TestCase("-")]
[TestCase("BXA")]
[TestCase("MMXK")]
public void TranslateRomanNumeral_WhenInvalidNumeralSyntax_RaiseException(string input)
{
var romanNumerals = new RomanNumerals();
Assert.Throws<ArgumentException>(() => romanNumerals.TranslateRomanNumeral(input));
}
[TestCase("IIII")]
[TestCase("CCCC")]
[TestCase("VV")]
[TestCase("IC")]
[TestCase("IM")]
[TestCase("XM")]
[TestCase("IL")]
[TestCase("MCDXCXI")]
[TestCase("MCDDXC")]
public void TranslateRomanNumeral_WhenInvalidNumeralSemantics_RaiseException(string input)
{
var romanNumerals = new RomanNumerals();
Assert.Throws<ArgumentException>(() => romanNumerals.TranslateRomanNumeral(input));
}
[TestCase("I", 1)]
[TestCase("II", 2)]
[TestCase("III", 3)]
[TestCase("IV", 4)]
[TestCase("XLII", 42)]
[TestCase("MMXIII", 2013)]
[TestCase("MXI", 1011)]
[TestCase("MCDXCIX", 1499)]
[TestCase("MMXXII", 2022)]
[TestCase("V", 5)]
[TestCase("VI", 6)]
[TestCase("CX", 110)]
[TestCase("CCCLXXV", 375)]
[TestCase("MD", 1500)]
[TestCase("MDLXXV", 1575)]
[TestCase("MDCL", 1650)]
[TestCase("MDCCXXV", 1725)]
[TestCase("MDCCC", 1800)]
[TestCase("MDCCCLXXV", 1875)]
[TestCase("MCML", 1950)]
[TestCase("MMXXV", 2025)]
[TestCase("MMC", 2100)]
[TestCase("MMCLXXV", 2175)]
[TestCase("MMCCL", 2250)]
[TestCase("MMCCCXXV", 2325)]
[TestCase("MMCD", 2400)]
[TestCase("MMCDLXXV", 2475)]
[TestCase("MMDL", 2550)]
[TestCase("MMMMMMMM", 8000)]
[TestCase("MMMMMMMMIV", 8004)]
public void TranslateRomanNumeral_WhenValidNumeral_Translate(string input, int output)
{
var romanNumerals = new RomanNumerals();
var result = romanNumerals.TranslateRomanNumeral(input);
Assert.That(result.Equals(output));
}
}
private static HashMap<Character, Integer> romanMap = new HashMap<>() {{
put('I', 1); put('V', 5); put('X', 10); put('L', 50);
put('C', 100); put('D', 500); put('M', 1000);
}};
private static int convertRomanToInt(String romanNumeral) {
int total = 0;
romanNumeral = romanNumeral.toUpperCase();
//add every Roman numeral
for(int i = 0; i < romanNumeral.length(); i++) {
total += romanMap.get(romanNumeral.charAt(i));
}
//remove the Roman numerals that are followed
//directly by a larger Roman numeral
for(int i = 0; i < romanNumeral.length()-1; i++) {
if(romanMap.get(romanNumeral.charAt(i))
< romanMap.get(romanNumeral.charAt(i+1))) {
total -= 2* romanMap.get(romanNumeral.charAt(i));
}
}
return total;
}
//note that the topmost solution does not solve this Roman numeral
//but mine does
//also note that this solution is a preference of simplicity over complexity
public static void main(String[] args) {
String rn = "CcLXxiV"; //274
System.out.println("Convert " + rn + " to " + convertRomanToInt(rn));
}
/*
this uses the string object Replace() & Split() methods
*/
int ToNumber(string roman){
/*
the 0 padding after the comma delimiter allows adding up the extra index produced by Split, which is not numerical
*/
string s1=roman.Replace("CM","900,0");
s1=s1.Replace("M","1000,0");
s1=s1.Replace("CD","400,0");
s1=s1.Replace("D","500,0");
s1=s1.Replace("XC","90,0");
s1=s1.Replace("C","100,0");
s1=s1.Replace("XL","40,0");
s1=s1.Replace("L","50,0");
s1=s1.Replace("IX","9,0");
s1=s1.Replace("X","10,0");
s1=s1.Replace("IV","4,0");
s1=s1.Replace("V","5,0");
s1=s1.Replace("I","1,0");
string[] spl=s1.Split(",");
int rlt=0;
for(int i=0;i<spl.Count();i++)
{
rlt+= Convert.ToInt32(spl[i].ToString());
}
return rlt;
}
private static Dictionary<char, int> RomanNumberMap = new Dictionary<char, int> {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000}
};
private const string RomanNumberValidationRegEx = "^(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$";
private static int ConvertToRomanNumberToInteger(string romanNumber)
{
if (!Regex.IsMatch(romanNumber, RomanNumberValidationRegEx))
{
throw new ArgumentOutOfRangeException(romanNumber);
}
int result = 0;
for (int i = 0; i < romanNumber.Length; i++)
{
int currentVal = RomanNumberMap[romanNumber[i]];
if (romanNumber.Length > i + 1)
{
int nextVal = RomanNumberMap[romanNumber[i + 1]];
if (nextVal > currentVal)
{
result = result + (nextVal - currentVal);
i++;
continue;
}
}
result = result + currentVal;
}
return result;
}
"IV".FromRoman() => 4
4.ToRoman() => "IV"