2014-09-24 80 views
0

我必須編寫一個Enum狀態的程序,它是50個2個字母的狀態縮寫(NY,FL等)。我需要製作一個程序,詢問用戶信息,他們需要輸入與狀態對應的2個字母。如何檢查它們的輸入是否有效,即匹配Enum狀態{AL,...,WY}中定義的2個字母的狀態?我想我可以做一個巨大的if語句檢查是否輸入==「AL」|| ... ||輸入==「WY」{do stuff} else {錯誤輸入與狀態不匹配},但必須爲所有50個狀態執行該操作會變得有點荒謬。有沒有更簡單的方法來做到這一點?如何確保用戶輸入允許的枚舉

另外,如果枚舉狀態被定義爲{AL,NY,FL},我怎樣才能將一個用戶輸入,這將是一個字符串,進入一個狀態?如果我將州改爲{「AL」,「NY」,「FL」}會更容易些,還是有另一種方法呢?

+0

請添加MCVE顯示你嘗試過什麼。 – Chantola 2014-09-24 17:32:57

回答

1

不幸的是,C++沒有提供將enum轉換爲字符串的便攜方式,反之亦然。可能的解決方案是填充std::map<std::string,State>(或哈希映射)並在轉換時進行查找。您可以手動填充此類地圖,也可以創建一個簡單腳本,該腳本將在.cpp文件中生成一個函數以填充此地圖並在構建過程中調用該腳本。您的腳本可以生成if/else語句,而不是填充地圖。

另一個更困難但更靈活和穩定的解決方案是使用像llvm這樣的編譯器,並根據編譯器生成的語法樹生成一個可生成此類函數的插件。

0

最簡單的方法是使用STL std::map,但對於不允許的學術練習(例如,可能只需要使用課程材料中涵蓋的技術)。

除非顯式初始化,否則枚舉是從零開始按順序編號的整數。鑑於此,您可以掃描字符串查找表,並將匹配的索引轉換爲枚舉。例如:

enum eUSstate 
{ 
    AL, AK, AZ, ..., NOSTATE 
} ; 

eUSstate string_to_enum(std::string inp) 
{ 
    static const int STATES = 50 ; 
    std::string lookup[STATES] = { "AL", "AK", "AZ" ... } ; 

    int i = 0 ; 
    for(i = 0; i < STATES && lookup[i] != inp; i++) 
    { 
     // do nothing 
    } 

    return static_cast<eUSstate>(i) ; 
} 

如果你也許不希望依靠蠻力的演員和在同一順序作爲枚舉,保持一個查找表,然後同時具有字符串和查找表可以使用匹配枚舉。

eUSstate string_to_enum(std::string inp) 
{ 
    static const int STATES = 50 ; 
    struct 
    { 
     std::string state_string ; 
     eUSstate state_enum ; 

    } lookup[STATES] { {"AL", AL}, {"AK", AK}, {"AZ", AL} ... } ; 

    eUSstate ret = NOSTATE ; 
    for(int i = 0; ret == NOSTATE && i < STATES; i++) 
    { 
     if(lookup[i].state_string == inp) 
     { 
      ret = lookup[i].state_enum ; 
     } 
    } 

    return ret ; 
} 

的查詢可以通過利用字母順序和執行二進制搜索進行優化,但對於美國50個州它是幾乎不值得的。

0

你需要的是一張桌子。因爲枚舉是線性的, 串的一個簡單的表就足夠了:

char const* const stateNames[] = 
{ 
    // In the same order as in the enum. 
    "NY", 
    "FL", 
    // ... 
}; 

然後:

char const* const* entry 
     = std::find(std::begin(stateNames), std::end(stateNames), userInput); 
if (entry == std::end(stateNames)) { 
    // Illegal input... 
} else { 
    State value = static_cast<State>(entry - std::begin(stateNames)); 

或者,也可以具有的數組:

struct StateMapping 
{ 
    State enumValue; 
    char const* name; 
    struct OrderByName 
    { 
     bool operator()(StateMapping const& lhs, StateMapping const& rhs) const 
     { 
      return std::strcmp(lhs.name, rhs. name) < 0; 
     } 
     bool operator()(StateMapping const& lhs, std::string const& rhs) const 
     { 
      return lhs.name < rhs; 
     } 
     bool operator()(std::string const& lhs, StateMapping const& rhs) const 
     { 
      return lhs < rhs.name; 
     } 
    }; 
}; 
StateMapping const states[] = 
{ 
    { NY, "NY" }, 
    // ... 
}; 

排序鑰匙,並用std::lower_bound

StateMapping::OrderByName cmp; 
StateMapping entry = 
     std::lower_bound(std::begin(states), std::end(states), userInput, cmp); 
if (entry == std::end(states) || cmp(userInput, *entry) { 
    // Illegal input... 
} else { 
    State value = entry->enumValue; 
    // ... 
} 

後者可能稍微快一點,但只有五十個 條目,我懷疑你會注意到不同之處。

當然,您不要手動編寫此代碼;你用一個簡單的腳本生成 。(過去,我有代碼,它會解析枚舉定義的C++源代碼,並從它們中生成 映射功能。它比聽起來簡單 ,因爲除了 之外,您可以忽略大量的C++代碼。用於跟蹤各個嵌套的)

0

的解決方案是簡單,但只適用於字符串中的2個字符(如在你的情況下):

#include <stdio.h> 
#include <stdint.h> 

enum TEnum 
{ 
    AL = 'LA', 
    NY = 'YN', 
    FL = 'LF' 
}; 


int _tmain(int argc, _TCHAR* argv[]) 
{ 

    char* input = "NY"; 
    //char* input = "AL"; 
    //char* input = "FL"; 



    switch(*(uint16_t*)input) 
    { 
     case AL: 
      printf("input AL"); 
      break; 
     case NY: 
      printf("input NY"); 
      break; 
     case FL: 
      printf("input FL"); 
      break; 
    } 
    return 0; 
} 

在上面的例子中我用枚舉具有雙字符代碼(它是合法的)並將一個輸入字符串傳遞給switch語句。我測試了它的結束工作!請注意枚舉中的單詞對齊。