Java中罗马数字和阿拉伯数字之间的转换

2025/04/10

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
即可立即永久解锁本站全部文章