2013-12-19 53 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