2013-12-19 52 views
1

我必须确保输入的字母只包含M,D,C,L,X,V和I,我已经完成了。多输入验证约束? C++

我的问题是,他们是罗马数字,而我也必须确保,如果一个较低值字符位于一个较高的值字符,它遵循罗马数字的规则:

  • 中号,D,C可以前面有一个字符2个点,所以CMDM没关系,但LM不是。
  • L,X,V只能前面有一个字母,所以XL没关系,但VL不是。

的7个字母代表值如下:

╔════════╦═══════╗ 
║ Symbol ║ Value ║ 
╠════════╬═══════╣ 
║ I  ║ 1  ║ 
║ V  ║ 5  ║ 
║ X  ║ 10 ║ 
║ L  ║ 50 ║ 
║ C  ║ 100 ║ 
║ D  ║ 500 ║ 
║ M  ║ 1,000 ║ 
╚════════╩═══════╝ 

这是我迄今:

void romanType::storeRoman() 
{ 
    locale loc; 
    bool valid = true; 

    do 
    { 
     valid = true; 
     cout << "please enter a roman numeral using no spaces:" << endl; 
     getline(cin, rNums); 

     for (i = 0; i < rNums.length(); ++i) 
     { 
      rNums[i] = toupper(rNums[i], loc); 
      if (rNums[i] == 'M' || rNums[i] == 'D' || rNums[i] == 'C' || 
       rNums[i] == 'L' || rNums[i] == 'X' || rNums[i] == 'V' || 
       rNums[i] == 'I') 
      { 
       continue; 
      } 
      valid = false; 
     } 

     cout << "input error please try again\n" << endl; 
    } while (!valid); 

    /* ... */ 

} 

它的工作原理,只要所有的人物都是罗马数字,但我不能为我的生活弄清楚如何实现我提到的其他两个约束。我编写了程序的大部分内容,但我花了大概6-7个小时试图让这一部分工作。请帮忙。

+1

请以某种方式让您的代码格式化,以供人们阅读。完全随机地格式化似乎是这里所有者不理解的代码的共同特征。 – Collin

+1

好吧,将定义的数字字符按照适当的顺序放在数组中,然后匹配输入字符并根据索引进行相对比较。 – OldProgrammer

+3

这些是一些非常奇怪的要求,他们不会让某些号码无法转移吗? –

回答

0

一种方法(从C心态)可能是列出合法字符,并对应于它们的法律“偏移”(如下定义):

#define LEGALCHAR 7 // number of possible legal letters in roman numerals 
char legalValues[LEGALCHAR] = {'I', 'V', 'X', 'L', 'C', 'D', 'M'}; 
int allowedDelta[LEGALCHAR] = {0, 1, 1, 1, 2, 2, 2}; 

并创建一个int IndexedNumeral阵列包含从索引匹配字符的legalValues,例如MMX将是{6,6,2}。然后遍历第二个到最后一个条目IndexedNumeral以比较(i-1,i)个字符与i个字符允许的合法偏移之间的差异。

diff = indexedNumeral[i] - indexedNumeral[i-1]; 
if (diff > allowedDelta[indexedNumeral[i]]) { 
    printf("illegal sequence: %i %i or %c %c\n", indexedNumeral[i-1], indexedNumeral[i], argv[1][i-1], argv[1][i]); 
    return 1; 
} 

当然还有其他方法。

2

遵循您的规则,有效的罗马数字MCMLIV(1954)将被视为无效,例如, C前面不能有ML不能跟前M。你的规则是错误的或不完整的。

但是如果改为使用这些规则(从Wikipedia拍摄),那么它会工作:

  • 的数字I可以VX之前被放置,使4个单位(IV)和9个单位(IX)分别
  • X可以LC之前被放置以使分别为40(XL)和90(XC
  • C可以放在DM之前,按照相同的模式制作400(CD)和900(CM)。现在

,你的函数基本需要执行两件事情:

  1. 检查无效字符(仅IVXLCDM被允许)
  2. 检查上述规则适用。

您的函数首先执行,但可以简化。我们所要做的就是在字符串中找到任何无效的字符。我们可以使用std::all_of检查所有字符是否有效。

// The string representing a roman number. 
std::string s = "MCMLIV"; 

// Check that the predicate is true for all elements in range. 
const std::string allowedChars = "IVXLCDM"; 
bool valid = std::all_of(std::begin(s), std::end(s), [&allowedChars] (char c) { 
    return allowedChars.find(::toupper(c)) != std::string::npos; 
}); 

if (!valid) { 
    std::cerr << "Input error" << std::endl; 
    return EXIT_FAILURE; 
} 

然后我们需要按照规则检查字符。我们可以使用std::adjacent_find这个:

// Check if we can find any pair that does not comply to the rules. 
auto it = std::adjacent_find(std::begin(s), std::end(s), [] (char lhs, char rhs) 
{ 
    lhs = std::toupper(lhs); // Transform to upper case. 
    rhs = std::toupper(rhs); // Transform to upper case. 
    return ((lhs == 'I' && rhs != 'V') && (lhs == 'I' && rhs != 'X')) || 
      ((lhs == 'X' && rhs != 'L') && (lhs == 'X' && rhs != 'C')) || 
      ((lhs == 'C' && rhs != 'D') && (lhs == 'C' && rhs != 'M')); 
}); 

if (it != std::end(s)) { 
    std::cerr << "Input error" << std::endl; 
    return EXIT_FAILURE; 
} 

就是这样!看到这个live example

编辑:

您还必须检查I不连续发生3次以上,所以不接受字符串作为IIIIIII。这应该是相当容易的。

+0

我相信这些规则是不完整的,IIIIIIIIIIIIIIII不应被接受。 –

+0

@ChristopherCreutzig规则规定“要制造4个单位(IV)和9个单位(IX)”,这可以解释为允许的“I”数量的限制。我添加了一个关于它的编辑,谢谢指出它。 – Snps