データでは、同じ製品がローマ数字で命名される場合もあれば、数字で命名される場合もあります。
Samsung Galaxy SII
聖句の例Samsung Galaxy S2
どのようII
に値に変換できます2
か?
データでは、同じ製品がローマ数字で命名される場合もあれば、数字で命名される場合もあります。
Samsung Galaxy SII
聖句の例Samsung Galaxy S2
どのようII
に値に変換できます2
か?
ここでいくつかの非常に複雑な解決策に気付きましたが、これは非常に単純な問題です。「例外」(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 を使用してみましたが、これは少し読みやすい解決策だと思いますが、最終的にすべての数値を追加し、それが例外の 1 つであることが判明した場合は後で 2 回減算しましたが、これは好きではありませんでした。後世のためにとにかくここに投稿します。
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;
}
これが私の解決策です
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");
}
}
}
単純なローマ数字コンバーターを作成しましたが、多くのエラー チェックは行われませんが、適切にフォーマットされたものすべてに対して動作するようです。
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;
}
これはスタックを使用します:
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;
}
}
}
編集
忘れてください!ここでBrunoLMソリューション
を見てください。
シンプルでエレガントです。
唯一の注意点は、ソースをチェックしないことです。
.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
}
}
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;
}