第一讲先从一个实例开始——我们需要完成一个遍历文件并统计单词出现次数的任务。分解功能:首先,按行读取文件并舍弃可能的空行。其次,将每一行都按照空格划分单词。因为可能存在标点符号,我们还需要将标点符号都删除。最后把行首或专有名词中出现的大写字母统一转换。最后将所有获取的字母放到一个关联容器中(map<string, int>)统计出现的次数。
一、从文件中读取并按行分割
(1)标准方法与参数
std::getline(basic_istream<charT,traits>& is, basic_string<charT,traits,Alloc>& str, charT delim)
参数1.输入流
参数2.接受字符串
*参数3.分割符
(2)代码实例
// 文件输入流 ifstream ifs("hello.txt"); // 行字符串向量类型 vector<string> paragraphs; string temp; // 遍历全文 while(std::getline(ifs, temp) { paragraphs.push_back(temp); }
二、以空格分隔字符串
(1)标准方法与参数
find_first_of (const basic_string& str, size_type pos = 0) const
参数1.字符串
*参数2.起始位置
substr (size_type pos = 0, size_type len = npos) const
*参数1.起始位置
*参数2.长度
(2)代码实例
const string key = " "; // 空格 vector<string> words; // 单词集合 string line; // 行 string::size_type pos = 0, prev = 0; // 系统相关变量。记录当前查找到空格的位置和前一个单词的起始位置。 while((pos = line.find_first_of(key, line)) != string::npos) { words.push_back(line.substr(pos, pos-prev)); prev = ++pos; }
三、大小写转换
(1)标准方法与参数
int tolower (int c)
参数.大写字母
返回.小写字母
(2)代码实例
string caps("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); // 大写字母集合 string::size_type pos = 0; string word; while((pos = word.find_first_of(pos, caps)) != string::npos) { w[pos] = tolower(w[pos]); // 用小写字母替换对应的大写 }
四、计数
(1)标准方法与参数
pair<iterator,bool> insert (const value_type& val)
参数1.value_type<K, V>(k, v) 插入值
*向map对象插入新值可以使用索引的方式,如map<string, int> m; m["hello"] = 37; 但是这会发生以下的事情,从而导致严重的性能损失:
-
一个未命名的临时string 对象被构造并传递给与map 类相关联的下标操作符这个对象用“hello”初始化;
-
一个新的键/值对被插入到m中当然键是一个“hello”对象持有Anna但是值是0,而不是37;
- 插入完成接着值被赋为37;
所以推荐做法是使用insert方法。
(2)代码实例
map<string, int> m; m.insert(map<string, int>::value_type("hello", 37));
五、完整代码
.h
#ifndef TEXTUTILS_H #define TEXTUTILS_H #include <string> // string getline #include <vector> // vector #include <fstream> // ifstream #include <iostream> // cout endl #include <stdlib.h> // exit #include <locale> // tolower #include <map> // map using namespace std; class TextUtils { public: TextUtils(); virtual ~TextUtils(); public: // 静态方法:单词统计 static map<string, int>* wordStatistics(string filename, string filter = ",.:;?\"!"); private: // 按照段落划分 void paragraphs(ifstream& ifs, vector<string>* p); // 获取单词集合 void words(vector<string>* p, vector<string>* w, const string filter = ",.:;?\"!"); // 小写替换 void lower(vector<string>* w); // 计数 void counter(map<string, int> *out, vector<string> *in); }; #endif // TEXTUTILS_H
.cpp
#include "TextUtils.h" map<string, int>* TextUtils::wordStatistics(string filename, string filter) { TextUtils utils; ifstream fin(filename.c_str(), ios::in); // 判断文件是否存在 if(!fin) { exit(-1); } // 声明段落容器 vector<string> p; utils.paragraphs(fin, &p); // 声明字母容器 vector<string> w; utils.words(&p, &w); // 大小写转换 utils.lower(&w); // 声明返回指针 map<string, int> *m = new map<string, int>; utils.counter(m, &w); return m; } void TextUtils::paragraphs(ifstream& ifs, vector<string>* p) { string temp; while(getline(ifs, temp, ‘/n‘)) { if(temp.size()) p->push_back(temp); } } void TextUtils::words(vector<string>* p, vector<string>* w, const string filter) { for(vector<string>::iterator it=p->begin(); it != p->end(); ++it) { string paragraph = *it; string::size_type pos = 0, prev_pos = 0; while((pos = paragraph.find_first_of(‘ ‘, pos)) != string::npos) { w->push_back(paragraph.substr(prev_pos, pos-prev_pos)); prev_pos = ++pos; } w->push_back(paragraph.substr(prev_pos, pos-prev_pos)); } // 遍历字母中的标点,删除 for(vector<string>::iterator it = w->begin(); it != w->end(); ++it) { string::size_type pos = 0; while((pos = (*it).find_first_of(filter, pos)) != string::npos) { (*it).erase(pos, 1); } } } void TextUtils::lower(vector<string>* w) { string caps("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); for(vector<string>::iterator it = w->begin(); it != w->end(); ++it) { string::size_type pos = 0; while((pos = (*it).find_first_of(caps, pos)) != string::npos) { (*it)[pos] = tolower((*it)[pos]); } } } void TextUtils::counter(map<string, int> *out, vector<string> *in) { for(vector<string>::iterator it = in->begin(); it != in->end(); ++it) { // 如果单词不存在,则在容器中插入新值。否则做自增操作 if(!out->count(*it)) { out->insert(map<string, int>::value_type(*it, 1)); } else { ++((*out)[*it]); // ++i的效率高于i++ } } }
总结:通过一个不难么简单例子作为C++学习的启蒙或许对有些初学者来说不那么友好。不过,我之所谓选择已这个例子因为它恰恰展现了这门语言的特点:高效。