检查罗马数字的有效性(困难)

check for the validity of a roman number (difficult)

我想编写一个函数来检查给定的罗马表示字符串是否正确。他们是很多不允许组合的情况:(我假设给定的字符串将代表 1 到 3999 之间的数字)

所以,我的想法是,与其检查不允许的组合,不如写下所有可能的允许组合,每次遇到不在其中的组合时,我们都会 return 错误。那是我的主意。不方便的是我的最终函数很长而且不太容易理解。

例如,我首先编写了一个函数来检查数千(当然如果它们存在),然后该函数 returns 我将使用的索引来对当前字符串进行子串以移动到下一部分(在这种情况下将有数百个):

private static int isThousandsValid(String str){
    int len = str.length();

    char a1 = str.charAt(0);
    char a2 = (len >= 2)? str.charAt(1) : ' ';
    char a3 = (len >= 3)? str.charAt(2) : ' ';

    if (a1 == 'M' && a2 == 'M' && a3 == 'M') //if we met that combinatin
        return 3; //we have to move after 3 digits to meet the beginning
                      //of the hundred digits
    else if (a1 == 'M' && a2 == 'M')   //same raisoning for other combinations
        return 2;

    else if (a1 == 'M') 
        return 1;

    else if (a1 == 'D' || a1 == 'C' || a1 == 'L'  || a1 == 'X' || a1 == 'V' || a1 == 'I'  )
        return 0;

    else return -1;

}

然后,我为百位、十位和个位写了同样的东西。百的例子:

private static int isHundredsValid(String str){
    if (str.isEmpty()) return 0;
    int len = str.length();

    char a1 = str.charAt(0);
    char a2 = (len >= 2)? str.charAt(1) : ' ';
    char a3 = (len >= 3)? str.charAt(2) : ' ';
    char a4 = (len >= 4)? str.charAt(3) : ' ';

    if (a1 == 'C' && a2 == 'M') 
        return 2;

    else if (a1 == 'D' && a2 == 'C' && a3 == 'C' && a4 == 'C')
        return 4;

    else if (a1 == 'D' && a2 == 'C' && a3 == 'C') 
        return 3;

    else if (a1 == 'D' && a2 == 'C') 
        return 2;

    else if (a1 == 'D') 
        return 1;

    else if (a1 == 'C' && a2 == 'D') 
        return 2;

    else if (a1 == 'C' && a2 == 'C' && a3 == 'C') 
        return 3;

    else if (a1 == 'C' && a2 == 'C') 
        return 2;

    else if (a1 == 'C') 
        return 1;

    else if (a1 == 'L'  || a1 == 'X' || a1 == 'V' || a1 == 'I'  )
        return 0;

    else return -1;     
}

然后,在我的最终函数中,我这样写:

    public static boolean isValidRoman(String str){
    str = str.trim(); //remove spaces
    if (str.isEmpty()) return false;

    int index1 = isThousandsValid(str);     
    String str1 = mySubstring(str, index1);

    int index2 = isHundredsValid(str1);     
    String str2 = mySubstring(str1, index2);

    int index3  = isTensValid(str2);        
    String str3 = mySubstring(str2, index3);

    int index4 = isUnitsValid(str3);        
    String str4 = mySubstring(str3, index4);

    if (str1.isEmpty() || str2.isEmpty() || str3.isEmpty())
        return true;

    if (index1 == -1 || index2 ==-1 || index3 == -1 || index4 == -1)
        return false;

    return str4.isEmpty(); //if we still have ANOTHER character after it terminates
}

最后,"mySubstring" 只是我用来重构和清除代码的一个简单函数:

 private static String mySubstring(String str, int index){
    if (index == -1 ) return str;
    else 
        return str.substring(index);
}

我有两个主要问题: 这个功能对你来说合适吗?我测试了很多例子,但我不太确定(我无法测试所有 3999 种可能的组合...)

是否可以改进?只是为了让它更干净或更具可读性? 有没有比写所有这些情况更简单的方法来检查罗马数字的有效性??

我会选择简短而疯狂的解决方案,并使用正则表达式匹配字符串:

public boolean isRoman(String s)
{
    return !s.isEmpty() 
           && s.matches("M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})");
}