我正在为我班上的“字典”工作。我有一个名为NumOfWordsInFile[]
的int数组,其中NumOfWordsInFile[0]
对应于A.txt中的单词数,NumOfWordsInFile[25]
对应于Z.txt
就像现在一样,我对26种不同的字母条件进行了巨大的转换。我有一个名为AddWord(string word)
的函数。 AddWord获取传递给它的单词的第一个字母,并将其插入相应的.txt文件中。现在这是问题所在。每次在A.txt中添加一个单词时,我必须将NumOfWordsInFile[0]
增加1.我能想到的唯一方法是使用这些巨大的开关。我还有一个deleteWord函数,如果删除该单词,则相反递减NumOfWordsInFile[]
。现在我不想要两个26箱开关,但问题是我不知道怎么做。现在我可以为删除功能做同样的事情,但我真的不希望有更多的代码行来完成。有更好的方法吗?
AddWord
功能中的开关示例:
case 'w':
if (numOfWordsInFile[22] < maxWordsPerFile) {
fout.open(fileName.data(), ios::app);
fout << word << " " << endl;
numOfWordsInFile[22]++;
if (totalWordsInDict < maxWordsInDict) {
totalWordsInDict++;
}
return(Dictionary::success);
} else {
return(Dictionary::failure);
}
case 'x':
if (numOfWordsInFile[23] < maxWordsPerFile) {
fout.open(fileName.data(),ios::app);
fout << word << " " << endl;
numOfWordsInFile[23]++;
if (totalWordsInDict < maxWordsInDict) {
totalWordsInDict++;
}
return(Dictionary::success);
} else {
return(Dictionary::failure);
}
删除功能。
bool Dictionary::DeleteAWord(string word)
{
ofstream fout;
ifstream fin;
string x;
string fileName="#.txt";
int count=0;
vector <string> words;
bool deleted=false;
fileName[0]=toupper(word[0]);
fin.open(fileName.data()); //makes the file depending on the first letter of the argument "word"
while (fin >> x)
{
words.push_back(x);
count++;//number of elements in vector
}
if (SearchForWord(x))
{
for ( ;count > 0; count--)
{
if (words[count-1] == word)
{
// cout << "Found word " << word << " during search, now deleting" << endl;
words.erase(words.begin()+(count-1));
deleted = true;
/*
This clearly doesn't work and is what I need help with, I know why it
doesn't work but I don't know how to make it better than having another
huge switch.
*/
numOfWordsInFile[toupper(word[0])]--;
/*
*/
totalWordsInDict--;
fin.close();
}
}
if (deleted)
{
fout.open(fileName.data());
for (int i = 0; i < words.size(); i++)
fout << words[i] << endl;
return(Dictionary::success);
}
return(Dictionary::failure);
}
return(Dictionary::failure);
}
答案 0 :(得分:7)
只是快速看一下,看起来你正在使用字母表中字母的位置来做事。
您可以使用以下语句替换所有switch语句:
int letter = (int)(ActualLetter - 'a');
if(numOfWordsInFile[letter]<maxWordsPerFile){
fout.open(fileName.data(),ios::app);
fout<<word<<" "<<endl;
numOfWordsInFile[letter]++;
if(totalWordsInDict<maxWordsInDict){
totalWordsInDict++;
}
return(Dictionary::success);
}else{
return(Dictionary::failure);
}
ActualLetter就像是'a',例如。
在相关的说明中,将来如果您实际上有大型switch语句,请考虑将代码封装在函数中:
switch (letter)
{
case 'a':
LetterA();
break;
case 'b':
LetterB();
break;
...
}
或者甚至更好,您可以使用多态来根据特定的派生类将C ++调度到您想要的方法:
class BaseLetter
{
...
public:
virtual void DoStuff() = 0;
};
class LetterA : public BaseLetter
{
public:
void DoStuff();
};
class LetterB : public BaseLetter
{
public:
void DoStuff();
};
void Foo(BaseLetter *letter)
{
// Use dynamic dispatch to figure out what to do
letter->DoStuff();
}
请注意,动态调度确实会有轻微的性能损失,而上述实际使用它是一个非常糟糕的地方。解决方案I,RedX和其他人发布的解决方案更适合您的具体示例。
答案 1 :(得分:6)
在使用C或C ++时可能遇到的大多数实际字符编码中,'a'
到'z'
是连续的,因此您可以通过执行{{1}来获取数组索引其中(c - 'a')
是您正在查看的c
。
答案 2 :(得分:6)
struct FileInfo {
int NumWords;
std::string Filename;
};
std::map<char, FileInfo> TheFiles;
FileInfo & FI = TheFiles[letter];
// Work with FI.NumWords and FI.Filename
可替换地:
std::vector<FileInfo> TheFiles;
FileInfo & FI = TheFiles[std::tolower(Letter) - 'a'];
答案 3 :(得分:3)
if(numOfWordsInFile[letter - 'A']<maxWordsPerFile){
fout.open(fileName.data(),ios::app);
fout<<word<<" "<<endl;
numOfWordsInFile[letter - 'A']++;
if(totalWordsInDict<maxWordsInDict){
totalWordsInDict++;
}
return(Dictionary::success);
}else{
return(Dictionary::failure);
}
只有在您的用例中只有英文字母时才能使用。
答案 4 :(得分:3)
Chars基本上是数字。 'a'是97,'b'是98,依此类推。
最简单的方法是简单地用numOfWordsInFile[n]
替换每个numOfWordsInFile[current_char - 'a']
,并且每个案例重复的整个代码可以驻留在一个函数中,如下所示:
int AddWord(char current_char) {
if(numOfWordsInFile[current_char - 'a']<maxWordsPerFile){
fout.open(fileName.data(),ios::app);
fout<<word<<" "<<endl;
numOfWordsInFile[current_char - 'a']++;
if(totalWordsInDict<maxWordsInDict){
totalWordsInDict++;
}
return(Dictionary::success);
}else{
return(Dictionary::failure);
}
}
有关更常见的解决方案,请阅读有关哈希映射和函数指针的信息(例如,对于每个字符,您可能希望分配不同的函数。
答案 5 :(得分:2)
C ++中的单个字符实际上只是与其ASCII值对应的数字。您可以相互减去字母以获取数值。因此,如果word[0]
包含字母A,则word[0] - 'A'
将为0
。
因此,您可以直接索引numOfWordsInFile
数组,根本不需要切换:numOfWordsInFiled[word[0] - 'A']
。
请注意,'A' and 'a'
具有不同的数值,因此如果您混合使用大写和小写,则必须执行一些额外的工作。
答案 6 :(得分:1)
如果您的文件是A.txt,请让您的数组索引为'A' - 'A'
(= 0),如果文件为B.txt,则让数组索引为'B' - 'A'
(= 1)等
答案 7 :(得分:1)
这取决于您想要的便携性或方式 国际化。如果你能够忽视这种可能性 第一个字母可能是重音字符,并假设 你永远不会在大型机或任何地方运行 否则使用EBCDIC,然后你可以将第一个字母转换为 一个特定的案例,并减去'a'或'A'(取决于具体情况) 从中获取索引。 C ++标准不保证 然而,这些字母是连续的,而且它们不在 EBCDIC,也不支持任何支持重音的编码 字符。至少,你必须测试一下 当然,第一个字符是一个字母。
因为处理国际化问题很困难 一般没有人使用编码,而且有些 编码是多字节的。对于单字节编码,它是 相当直接使用映射表;一张桌子 256个条目,由第一个字母索引(转换为无符号 char),它将索引返回到您的表中。对于多字节 编码,如UTF-8,问题更复杂:你可以 将UTF-8序列中的初始字符转换为int, 但你最终可能会得到大约一百万或更多的价值 不希望有一百万个条目的表(大多数都是 完全无关紧要。一个简单的解决方案可能是添加 “其他”的第27个条目。 (这也会像“文字”一样 “第二”。)
一种非常便携的方法是:
int mappingTable[256];
std::fill_n(mappingTable, 256, 26);
static char const upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ;
static char const lower[] = "abcdefghijklmnopqrstuvwxyz;
for (int i = 0; i < 26; ++ i) {
mappingTable[upper[i]] = i;
mappingTable[lower[i]] = i;
}
不要忘记将初始字符强制转换为unsigned char 在编制索引之前。