C# 罗马数字到整数

C# 罗马数字到整数,c#,roman-numerals,C#,Roman Numerals,我有一个产品的转让,不幸的是必须得到产品名称匹配。这里最大的问题是我可能会因为罗马数字而得到重复的产品。有时同一产品会以罗马数字命名,有时则是常规数字 这些产品是移动设备。示例-三星Galaxy SII-三星Galaxy S2 人们怎么能编写这样的函数呢?我刚刚编写了一个简单的罗马数字转换器,但它并没有进行大量的错误检查,但它似乎适用于所有我能够正确格式化的东西 public static int ConvertRomanNumtoInt(string strRomanValue) {

我有一个产品的转让,不幸的是必须得到产品名称匹配。这里最大的问题是我可能会因为罗马数字而得到重复的产品。有时同一产品会以罗马数字命名,有时则是常规数字

这些产品是移动设备。示例-三星Galaxy SII-三星Galaxy S2


人们怎么能编写这样的函数呢?

我刚刚编写了一个简单的罗马数字转换器,但它并没有进行大量的错误检查,但它似乎适用于所有我能够正确格式化的东西

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"