1. 简介
古罗马人开发了自己的数字系统,称为罗马数字,该系统使用不同值的字母来表示数字,罗马数字至今仍在一些小规模的应用中使用。
在本教程中,我们将实现简单的转换器,将数字从一个系统转换为另一个系统。
2. 罗马数字
在罗马系统中,我们有7个符号代表数字:
- I代表1
- V代表5
- X代表10
- L代表50
- C代表100
- D代表500
- M代表1000
最初,人们习惯用IIII表示4,用XXXX表示40,这样读起来会很不舒服,而且很容易将相邻的4个符号误认为是3个符号。
罗马数字使用减法来避免此类错误,4不是用4乘以1(IIII)表示,而是说5减1(IV)。
从我们的角度来看这有多重要?这很重要,因为我们可能需要检查下一个符号来确定是应该加还是减,而不是简单地逐个符号地相加数字。
3. 模型
让我们定义一个枚举来表示罗马数字:
enum RomanNumeral {
I(1), IV(4), V(5), IX(9), X(10),
XL(40), L(50), XC(90), C(100),
CD(400), D(500), CM(900), M(1000);
private int value;
RomanNumeral(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static List<RomanNumeral> getReverseSortedValues() {
return Arrays.stream(values())
.sorted(Comparator.comparing((RomanNumeral e) -> e.value).reversed())
.collect(Collectors.toList());
}
}
请注意,我们定义了额外的符号来帮助进行减法运算,我们还定义了一个名为getReverseSortedValues()的附加方法,此方法将允许我们按降序明确检索定义的罗马数字。
4. 罗马数字转阿拉伯数字
罗马数字只能表示1到4000之间的整数,我们可以使用以下算法将罗马数字转换为阿拉伯数字(按从M到I的反向顺序迭代符号):
LET numeral be the input String representing an Roman Numeral
LET symbol be initialy set to RomanNumeral.values()[0]
WHILE numeral.length > 0:
IF numeral starts with symbol's name:
add symbol's value to the result
remove the symbol's name from the numeral's beginning
ELSE:
set symbol to the next symbol
4.1 实现
接下来我们可以用Java实现该算法:
public static int romanToArabic(String input) {
String romanNumeral = input.toUpperCase();
int result = 0;
List<RomanNumeral> romanNumerals = RomanNumeral.getReverseSortedValues();
int i = 0;
while ((romanNumeral.length() > 0) && (i < romanNumerals.size())) {
RomanNumeral symbol = romanNumerals.get(i);
if (romanNumeral.startsWith(symbol.name())) {
result += symbol.getValue();
romanNumeral = romanNumeral.substring(symbol.name().length());
} else {
i++;
}
}
if (romanNumeral.length() > 0) {
throw new IllegalArgumentException(input + " cannot be converted to a Roman Numeral");
}
return result;
}
4.2 测试
最后,我们可以测试一下实现:
@Test
void given2018Roman_WhenConvertingToArabic_ThenReturn2018() {
String roman2018 = "MMXVIII";
int result = RomanArabicConverter.romanToArabic(roman2018);
assertThat(result).isEqualTo(2018);
}
5. 阿拉伯数字转罗马数字
我们可以使用以下算法将阿拉伯数字转换为罗马数字(按从M到I的相反顺序迭代符号):
LET number be an integer between 1 and 4000
LET symbol be RomanNumeral.values()[0]
LET result be an empty String
WHILE number > 0:
IF symbol's value <= number:
append the result with the symbol's name
subtract symbol's value from number
ELSE:
pick the next symbol
5.1 实现
接下来,我们现在可以实现该算法:
public static String arabicToRoman(int number) {
if ((number <= 0) || (number > 4000)) {
throw new IllegalArgumentException(number + " is not in range (0,4000]");
}
List<RomanNumeral> romanNumerals = RomanNumeral.getReverseSortedValues();
int i = 0;
StringBuilder sb = new StringBuilder();
while ((number > 0) && (i < romanNumerals.size())) {
RomanNumeral currentSymbol = romanNumerals.get(i);
if (currentSymbol.getValue() <= number) {
sb.append(currentSymbol.name());
number -= currentSymbol.getValue();
} else {
i++;
}
}
return sb.toString();
}
5.2 测试
最后,我们可以测试一下实现:
@Test
void given1999Arabic_WhenConvertingToRoman_ThenReturnMCMXCIX() {
int arabic1999 = 1999;
String result = RomanArabicConverter.arabicToRoman(arabic1999);
assertThat(result).isEqualTo("MCMXCIX");
}
6. 总结
在这篇简短的文章中,我们展示了如何在罗马数字和阿拉伯数字之间进行转换。
我们使用枚举来表示罗马数字集,并创建了一个实用程序类来执行转换。
Show Disqus Comments
Post Directory
扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章
