将 c++ 字符串映射到枚举以便获取用户输入
Mapping c++ string to an enum in order to take user input
我正在尝试设计一个类来表示一张牌,我决定使用枚举来表示等级和花色。但是,我需要能够从用户那里获取输入,不幸的是,不可能直接从 cin 获取枚举。
出于这个原因,我打算接受一个字符串并使用std::map
将每个字符串映射到它所表示的枚举值(如本问题中所述)。我也不希望我的输入区分大小写,所以我创建了一个正则表达式,应该在匹配之前将所有字符转换为小写。
我想出的代码在这里:
istream& operator>>(istream& is, Card& d)
{
std::map<std::string,Card::Rank> mr;
std::map<std::string,Card::Suit> ms;
mr[std::regex("/two/i")] = Card::TWO;
mr[std::regex("/three/i")] = Card::THREE;
mr[std::regex("/two/i")] = Card::FOUR;
mr[std::regex("/two/i")] = Card::FIVE;
mr[std::regex("/two/i")] = Card::SIX;
mr[std::regex("/two/i")] = Card::SEVEN;
mr[std::regex("/two/i")] = Card::EIGHT;
mr[std::regex("/two/i")] = Card::NINE;
mr[std::regex("/two/i")] = Card::TEN;
mr[std::regex("/two/i")] = Card::JACK;
mr[std::regex("/two/i")] = Card::QUEEN;
mr[std::regex("/two/i")] = Card::KING;
ms[std::regex("/clubs/i")] = Card::CLUBS;
ms[std::regex("/diamonds/i")] = Card::DIAMONDS;
ms[std::regex("/hearts/i")] = Card::HEARTS;
ms[std::regex("/spades/i")] = Card::SPADES;
string srank, ssuit;
char c1;
if (is >> srank >> c1 >> ssuit)
{
if (c1 == 'of')
{
Card::Rank rank = mr[srank];
Card::Suit suit = ms[ssuit];
d = Card(rank, suit);
}
else
{
is.clear(ios_base::failbit);
}
}
return is;
}
但是,在编译时我收到此错误:
error C2679: binary '[' : no operator found which takes a right-hand operand of type 'std::basic_regex<_Elem>' (or there is no acceptable conversion)
with
[
_Elem=char
]
c:program files (x86)microsoft visual studio 11.0vcincludemap(173): could be 'Card::Rank &std::map<_Kty,_Ty>::operator [](std::basic_string<_Elem,_Traits,_Alloc> &&)'
with
[
_Kty=std::string,
_Ty=Card::Rank,
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
c:program files (x86)microsoft visual studio 11.0vcincludemap(190): or 'Card::Rank &std::map<_Kty,_Ty>::operator [](const std::basic_string<_Elem,_Traits,_Alloc> &)'
with
[
_Kty=std::string,
_Ty=Card::Rank,
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
while trying to match the argument list '(std::map<_Kty,_Ty>, std::basic_regex<_Elem>)'
with
[
_Kty=std::string,
_Ty=Card::Rank
]
and
[
_Elem=char
]
etc.
我以前从未使用过地图,我真的不明白我做错了什么;从我设法挖掘的说明来看,这应该有效。
您声明mr
是从字符串到等级的映射。您正在尝试使用regex
作为密钥。但是正则表达式不是字符串。选择一个,然后始终如一地使用它。
基于您拥有的解决方案:
std::regex
不是std::string
,这些是完全不同的类型。我也怀疑,如果您可以使用std::regex
作为地图键获得任何合理的结果。更重要的是,std::map 永远不会像你预期的那样工作。如果你想根据正则表达式列表测试一个字符串并选择匹配的字符串,你必须这样做:迭代所有正则表达式并测试每个正则表达式。如果您要放松这些正则表达式,这就是您所需要的。
更简单的方法是将所有读取字符串转换为小写,然后使用标准的字符串映射。像这样:
#include <cctype>
static inline void stringToLower(std::string &s) {
for (uint i = 0; i < s.size(); ++i) {
s[i] = tolower(s[i]);
}
}
istream& operator>>(istream& is, Card& d)
{
std::map<std::string,Card::Rank> mr;
std::map<std::string,Card::Suit> ms;
mr["two"] = Card::TWO;
mr["three"] = Card::THREE;
...
mr["king"] = Card::KING;
ms["clubs"] = Card::CLUBS;
...
string srank, ssuit, c1;
if (is >> srank >> c1 >> ssuit)
{
stringToLower(c1);
if (c1 == "of")
{
stringToLower(srank);
stringToLower(ssuit);
Card::Rank rank = mr[srank];
Card::Suit suit = ms[ssuit];
d = Card(rank, suit);
}
else
{
is.clear(ios_base::failbit);
}
}
return is;
}
请注意,我将 c1 更改为字符串。在 yout 版本中,c1 将是 srank 之后的第一个字符(这将是一些空间)。此外,char
值永远不能等于 'of'
('of'
的类型为 int)。我将其更改为 "of"
(双引号),类型为 const char *
.请记住,如果 c1 char*
,它将无法正常工作。
顺便说一下,为每个<<
调用分别创建mr
和ms
映射是非常低效的。考虑使用某种单例。可能的解决方案可能是这样的:
static std::map<std::string,Card::Rank> createmr() {
std::map<std::string,Card::Rank> mr;
mr["two"] = Card::TWO;
mr["three"] = Card::THREE;
...
mr["king"] = Card::KING;
return mr;
}
static std::map<std::string,Card::Rank> createms() {
std::map<std::string,Card::Rank> ms;
ms["clubs"] = Card::CLUBS;
...
return ms;
}
istream& operator>>(istream& is, Card& d)
{
static std::map<std::string,Card::Rank> mr = createmr(); // note `static` keyword
static std::map<std::string,Card::Suit> ms = createms();
...
}
说明:我在这里使用了static
关键字,在两种不同的地方。一个是在函子声明之前。这意味着static
,此函数在其他源文件中将不可用。我还在mr
和ms
声明中使用它。这意味着,这些变量对于定义它们的所有函数调用都是通用的(在本例中为 operator>>
)。这样做的一个结果是,createmr() 和 createms() 只会在第一次调用运算符时被调用一次。
可能更好的方法是在函数外部定义mr
和ms
:
static std::map<std::string,Card::Rank> mr = createmr(); // note `static` keyword
static std::map<std::string,Card::Suit> ms = createms();
istream& operator>>(istream& is, Card& d)
{
...
}
这里的关键字static
意味着这些变量(现在是全局变量)将无法从此源文件外部访问。这里可以省略它,但最好标记static
所有函数和全局变量,这些函数和全局变量不会在外部使用。
- 如何获取用户输入的算术表达式,如 5-8+7*4-8+9 或 1+5?
- C++如何使用表达式获取用户输入?
- 有没有办法获取用户操作系统的ANSI转义码?
- 当PSO细粒度策略对使用AdsGetObject MSDN API的Windows操作系统生效时,如何获取用户密码到期日
- C++ .我正在尝试通过使用开关内的数组来获取用户输入,但是当我运行代码时,它显示分段错误?
- 使用 Firebase 从C++获取用户的电话号码
- 从 R 控制台获取用户输入:Rcpp 和 std::cin
- 如何使用字符串获取用户控制台输入
- 循环以使用 cstring 数组 c++ 获取用户输入
- 尝试获取用户输入和cout消息期望,当我输入一个有效名称时,它将所有这些命名
- 获取用户输入以形成链表
- 尝试编写进程内存并获取用户定义的文字运算符未找到
- 如何使用 C++17 std::文件系统获取用户的主目录?
- C |获取用户输入而无需给出值
- 如何在消息文件中获取用户定义的字段
- 从Windows上的系统工作的服务中获取用户文档文件夹.C++
- 如何阻止 cin.getline() 导致控制台在找不到分隔符时重复获取用户输入?
- C++:获取用户通过cin输入的数据类型
- 如何在C 中使用我的服务来获取用户的SID和用户名
- 结构数组:无需致电并获取用户输入的匹配函数