【问题标题】:check for the validity of a roman number (difficult)检查罗马数字的有效性(困难)
【发布时间】:2016-06-11 18:58:19
【问题描述】:

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

  • 同一字符不能连续出现超过 3 次:例如:IIII 为假。
  • 不允许某些组合:DD 为假('D' + 'D' = 500 + 500 = 1000 即 M
  • 我们不能在后面减去一个字符并添加相同的字符:例如,如果 IX 为 9,则 IXI 是不正确的事件,它不等于 9 + 1
  • 最高有效数字必须在开头,而不是在中间或结尾。例如:XM(代表 1010)是假的,而 MX 是正确的。
  • 等等……

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

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

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 种可能的组合......)

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

【问题讨论】:

  • 查看工作代码,CodeReview 是去的地方。

标签: java roman-numerals


【解决方案1】:

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

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

【讨论】:

  • 如果你的问题是家庭作业,那么你应该认真学习正则表达式,并确保在提交这个解决方案之前你可以解释正则表达式的每个部分......
  • 它有效,但老实说我并没有很好地理解它。你能解释一下或给我一个链接来理解java中的正则表达式吗?谢谢!
  • 也许wikipedia 可以作为一个起点。还有一个Java tutorial。然后你当然总是有javadoc。正则表达式是您专业编程工具箱中的一个很好的基石!
  • 我还找到了一个stackoverflow article,其中讨论了罗马数字和正则表达式的内容!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 2014-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多