14

在数据中,有时相同的产品会用罗马数字命名,而其他时候会用数字命名。

示例 Samsung Galaxy SII经文Samsung Galaxy S2

如何将II其转换为价值2

4

20 回答 20

26

我注意到这里有一些非常复杂的解决方案,但这是一个非常简单的问题。我提出了一个解决方案,避免了对“异常”(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在字符串上使用 a,我认为这是一个更易读的解决方案,但我最终将每个数字相加,然后如果结果是我不喜欢的例外之一,则将其减去两次。无论如何,我都会在这里发布以供后代使用。

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;
}
于 2014-10-31T05:05:51.583 回答
10

这是我的解决方案

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



        }

    }
于 2017-07-12T17:42:03.630 回答
6

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

  • 将 I 映射到 1,V 映射到 5,X 映射到 10,L 映射到 50,C 映射到 100,D 映射到 500,M 映射到 1000。
  • 使用一个单独的 foreach 循环(foreach故意使用,保留先前的值)。
  • 将映射的数字添加到总数中。
  • 减去之前添加的数字的两倍,如果 I 在 V 或 X 之前,X 在 L 或 C 之前,C 在 D 或 M 之前(此处并非所有字符都允许!)。
  • 在空字符串、错误字母或不允许用于减法的字符上返回 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;
}
于 2015-01-16T03:43:00.720 回答
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;
}
于 2013-02-15T20:49:51.740 回答
3

我来到这里寻找罗马数字解析器的小型实现,但在大小和优雅方面对所提供的答案并不满意。我将最终的递归实现留在这里,以帮助其他人搜索小型实现。


通过递归转换罗马数字

  • 该算法也能够处理不相邻的数字(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;
}

尝试使用这个 .Netfiddle:https ://dotnetfiddle.net/veaNk3

它是如何工作的?

该算法通过从罗马数字中获取最高值并递归地加/减文字剩余左/右部分的值来计算罗马数字的值。

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
于 2017-12-07T12:52:59.700 回答
2

使用Humanizer库,您可以使用FromRoman扩展将罗马数字更改为数字

"IV".FromRoman() => 4

并使用ToRoman扩展进行反向操作。

4.ToRoman() => "IV"
于 2021-04-17T09:05:34.047 回答
1

完成“减法”语义检查的解决方案

当前的解决方案都没有完全满足“减法”的整套规则。“IIII”-> 是不可能的。每个解决方案的结果都是 4。字符串:“CCCC”、“VV”、“IC”、“IM”也是无效的。

一个很好的检查语义的在线转换器是https://www.romannumerals.org/converter 所以,如果你真的想做一个完整的语义检查,它要复杂得多。

我的方法是首先编写带有语义检查的单元测试。然后写代码。然后用一些 linq 表达式减少循环。

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

在代码部分之后,有一个部分包含我的单元测试。

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));
    }
}
于 2019-03-13T16:49:09.567 回答
1
private static int convertRomanToInt(String romanNumeral)
{
    Dictionary<Char, Int32> romanMap = new Dictionary<char, int>
    {
        {'I', 1 },
        {'V', 5},
        {'X', 10},
        {'L', 50},
        {'C', 100},
        {'D', 500},
        {'M', 1000}
    };

    Int32 result = 0;
    for (Int32 index = romanNumeral.Length - 1, last = 0; index >= 0; index--)
    {
        Int32 current = romanMap[romanNumeral[index]];
        result += (current < last ? -current : current);
        last = current;
    }

    return result;
}
于 2021-03-18T00:11:35.903 回答
1

System.Linq从这个借了很多。Stringimplements 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;
    }
于 2015-11-17T06:31:50.637 回答
1
    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;
    }
于 2021-02-16T21:16:13.673 回答
0

我将通过在 .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 
    }
}
于 2014-07-22T05:25:58.487 回答
0

这是我在 JavaScript 中的 O(n) 解决方案

const NUMERAL = {
    'I': 1,
    'V': 5,
    'X': 10,
    'L': 50,
    'C': 100,
    'D': 500,
    'M': 1000,
}

var romanToInt = function(s) {
    if (s.length === 1) return +NUMERAL[s];

    let number = 0;
    for (let i = 0; i < s.length; i++) {
        let num = +NUMERAL[s[i]];
        let prev = +NUMERAL[s[i-1]];
        
        if (prev < num) number += num - (2 * prev);
        else number += num;
    }
    
    return number;
};

于 2021-09-28T12:18:58.830 回答
0

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

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解决方案。 它简单而优雅。 唯一需要注意的是它不检查来源。

于 2016-02-17T17:27:12.643 回答
0

这个使用堆栈:

    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;
    }
于 2016-01-26T21:05:28.847 回答
0

这是我的解决方案:

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

以下是这些方法如何工作的说明:

转阿拉伯数字

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

ToRomanNumber:

我从给定的阿拉伯数字开始聚合。对于每一步,数字将除以罗马字母的等效数字。然后,该除法的其余部分是下一步的输入。除法结果将被转换为等效罗马数字字符,该字符将附加到结果字符串中。

于 2017-04-03T12:33:36.937 回答
0

FWIW,这是 David DeMar 答案的“尝试解析”版本:

private static readonly Dictionary<char, int> _romanMap = new Dictionary<char, int>() { { 'I', 1 }, { 'V', 5 }, { 'X', 10 }, { 'L', 50 }, { 'C', 100 }, { 'D', 500 }, { 'M', 1000 } };

public static bool TryParseRoman(string text, out int value)
{
    value = 0;
    if (string.IsNullOrEmpty(text))
        return false;

    var number = 0;
    for (var i = 0; i < text.Length; i++)
    {
        if (!_romanMap.TryGetValue(text[i], out var num))
            return false;

        if ((i + 1) < text.Length)
        {
            if (!_romanMap.TryGetValue(text[i + 1], out var num2))
                return false;

            if (num < num2)
            {
                number -= num;
                continue;
            }
        }

        number += num;
    }

    value = number;
    return true;
}
于 2022-01-18T14:37:46.563 回答
0
/*
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;
}
于 2021-01-26T17:11:04.450 回答
0

我参考了这个博客。您可以将罗马数字反转,然后进行比较会更容易进行比较。
public static int pairConversion(int dec, int lastNum, int lastDec) { if (lastNum > dec) return lastDec - dec; 否则返回 lastDec + dec;}

    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;

    }
于 2015-10-17T18:40:30.307 回答
0
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));
}
于 2019-07-31T21:52:59.043 回答
-4
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;
}
于 2013-02-15T18:12:55.243 回答