罗马数字为整数(Roman numerals to integers)

2019-07-19 23:51发布

我有,不幸的是要得到按产品名称匹配的产品转移。 这里最大的问题是,我可能会得到重复的产品是考虑罗马数字的。 有时候,同样的产品将与罗马数字来命名,其他时间这将是一个常规的一个。

我是google搜索也许已经取得字符串函数来转换这一点,但没有运气。 我想这不会是很难让我自己,但我很想听听你对如何处理这种情况的一些意见,如果你还知道一个已经取得函数,这样做,命名。

编辑:该产品是移动小工具。 示例 - 三星Galaxy SII - 三星Galaxy S2

Answer 1:

我在这里发现了一些非常复杂的解决方案,但是这是一个非常简单的问题。 我提出,避免了需要进行硬编码的“例外”(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;
}

我最初尝试使用foreach上,我认为这是一个稍微更可读解绳子,但我最终加入的每一个数字减去了两次以后,如果它原来是例外,这是我不喜欢的一个。 我会在这里反正它张贴在为后人。

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;
}


Answer 2:

一个更简单易读的C#实现的是:

  • 映射I至1,V至5,X 10,L 50,C至100,d 500,M至1000。
  • 使用一个单一的foreach循环(在目的而使用的foreach,与上次值的保持)。
  • 添加映射数与总。
  • 减去两倍数量的前添加,如果我d或M之前L或C,C之前V或X,X之前(不是所有字符都在这里允许!)。
  • 在空字符串,打错一个字母或不允许字符用于减法返回0(在罗马数字中不使用)。
  • 备注:它仍然没有完全完成,我们没有检查所有可能的条件,有效输入字符串!

码:

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;
}


Answer 3:

我写了一个简单的罗马数字转换器就在刚才,但它不会做一大堆的错误检查,但它似乎一切工作,我可以扔掉它是正确的格式。

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;
}


Answer 4:

这是我的解决办法

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");
            }



        }

    }


Answer 5:

借了很多从System.Linq就这一个。 String实现IEnumerable<char> ,所以我因为我们反正它当作一个枚举对象是适当的。 测试它针对一串随机数,包括1,3,4,8,83,99,404,555,846,927,1999,2420的。

    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;
    }


Answer 6:

我降落在这里寻找一个小的实现一个罗马数字解析器的,而是由提供的答案在尺寸和优雅的方面并不满足。 我在这里留下我的最后,递归实现,帮助别人寻找一个小的实现。


通过转换递归罗马数字

  • 该算法是能够非相邻标记以及(FE XIIX )。
  • 此实现可仅与形成阱(字符串匹配工作/[mdclxvi]*/i )罗马数字。
  • 执行不针对速度进行了优化。
// returns the value for a roman literal
private static int romanValue(int index)
{
    int basefactor = ((index % 2) * 4 + 1); // either 1 or 5...
    // ...multiplied with the exponentation of 10, if the literal is `x` or higher
    return index > 1 ? (int) (basefactor * System.Math.Pow(10.0, index / 2)) : basefactor;
}

public static int FromRoman(string roman)
{
    roman = roman.ToLower();
    string literals = "mdclxvi";
    int value = 0, index = 0;
    foreach (char literal in literals)
    {
        value = romanValue(literals.Length - literals.IndexOf(literal) - 1);
        index = roman.IndexOf(literal);
        if (index > -1)
            return FromRoman(roman.Substring(index + 1)) + (index > 0 ? value - FromRoman(roman.Substring(0, index)) : value);
    }
    return 0;
}

它是如何工作的?

该算法通过计算获取从罗马数字的最高值和加法/减法递归字面的剩余左/右部分的价值的一个罗马数字的值。

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


Answer 7:

我将在.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

C#

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class Form1
{
    int[] indx = {
        1,
        2,
        3,
        4,
        5,
        10,
        50,
        100,
        500,
        1000
        // initialize array of integers 
    };
    string[] row = {
        "I",
        "II",
        "III",
        "IV",
        "V",
        "X",
        "L",
        "C",
        "D",
        "M"
        //Carasponding roman letters in for the numbers in the array
    };
        // integer to indicate the position index for link two arrays 
    int limit = 9;
        //string to store output
    string output = "";
    private void Button1_Click(System.Object sender, System.EventArgs e)
    {
        int num = 0;
        // stores the input 
        output = "";
        // clear output before processing
        num = Convert.ToInt32(txt1.Text);
        // get integer value from the textbox
        //Loop until the value became 0
        while (num > 0) {
            num = find(num);
            //call function for processing
        }
        txt2.Text = output;
        // display the output in text2
    }
    public int find(int Num)
    {
        int i = 0;
        // loop variable initialized with 0
        //Loop until the indx(i).value greater than or equal to num
        while (indx(i) <= Num) {
            i += 1;
        }
        // detemine the value of limit depends on the itetration
        if (i != 0) {
            limit = i - 1;
        } else {
            limit = 0;
        }
        output = output + row(limit);
        //row(limit) is appended with the output
        Num = Num - indx(limit);
        // calculate next num value
        return Num;
        //return num value for next itetration 
    }
}


Answer 8:

我从这个参考博客 。 你可以只扭转罗马数字,那么所有的事情会更容易比较,作出比较。
公共静态INT pairConversion(INT分解,INT lastNum,INT lastDec){如果(lastNum>分解)返回lastDec - 分解; 否则返回lastDec +分解; }

    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;

    }


Answer 9:

这一次使用堆栈:

    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;
    }


Answer 10:

我写这个只是使用数组。
我在这里省略了测试代码,但看起来它工作正常。

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;
        }
    }
}

编辑
忘掉它 !
只要看看BrunoLM解决方案在这里 。
这是简单而优雅。
唯一需要注意的是,它不检查源。



Answer 11:

这是我的解决方案:

    /// <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
            );
    }

这里的方法是如何工作的说明:

ToArabicNumber

首先聚集步骤是更换罗马数字的特殊情况下(例如:IV - > IIII)。 第二聚合步骤简单地总结了罗马字母的等效阿拉伯数字(例如,V - > 5)

ToRomanNumber:

我开始用给定的阿拉伯数字聚集。 用于每个步骤的数目将由罗马字母的当量数来划分。 在这个除法的余数是然后用于下一步骤的输入。 除法结果将被转换为将被添加到结果字符串等效罗马数字字符。



Answer 12:

与履行“减记法”语义检查解决方案

目前的解决方案中没有完全履行了“减记法”的一整套规则。 “IIII” - >是不可能的。 每个解决方案的结果4.还字符串:“CCCC”,“VV”,“IC”,“IM”是无效的。

一个良好的网上转换器,用于检查语义https://www.romannumerals.org/converter所以,如果你真的想要做一个完全语义检查,它要复杂得多。

我的方法是先写单元测试与语义检查。 然后写代码。 然后,以减少一些LINQ表达式的循环。

也许有一个聪明的解决方案,但我认为下面的代码fullfills规则的罗马数字字符串转换。

该代码段后,有一个与我的单元测试的部分。

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));
    }
}


Answer 13:

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;
}


文章来源: Roman numerals to integers