C++學習筆記(一)——一個字符串分割和統計的工具(TextUtils)

第一講先從一個實例開始——咱們須要完成一個遍歷文件並統計單詞出現次數的任務。分解功能:首先,按行讀取文件並捨棄可能的空行。其次,將每一行都按照空格劃分單詞。由於可能存在標點符號,咱們還須要將標點符號都刪除。最後把行首或專有名詞中出現的大寫字母統一轉換。最後將全部獲取的字母放到一個關聯容器中(map<string, int>)統計出現的次數。ios

1、從文件中讀取並按行分割性能

(1)標準方法與參數學習

std::getline(basic_istream<charT,traits>& is, basic_string<charT,traits,Alloc>& str, charT delim)spa

參數1.輸入流指針

參數2.接受字符串code

*參數3.分割符對象

(2)代碼實例blog

// 文件輸入流
ifstream ifs("hello.txt");
// 行字符串向量類型
vector<string> paragraphs;

string temp;
// 遍歷全文
while(std::getline(ifs, temp) {
    paragraphs.push_back(temp);
}

2、以空格分隔字符串索引

(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;
}

3、大小寫轉換

(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]); // 用小寫字母替換對應的大寫
}

 

4、計數

(1)標準方法與參數

pair<iterator,bool> insert (const value_type& val)

參數1.value_type<K, V>(k, v) 插入值

*向map對象插入新值可使用索引的方式,如map<string, int> m; m["hello"] = 37; 可是這會發生如下的事情,從而致使嚴重的性能損失:

  1. 一個未命名的臨時string 對象被構造並傳遞給與map 類相關聯的下標操做符這個對象用「hello」初始化;

  2. 一個新的鍵/值對被插入到m中固然鍵是一個「hello」對象持有Anna可是值是0,而不是37;

  3. 插入完成接着值被賦爲37;

因此推薦作法是使用insert方法。

(2)代碼實例

map<string, int> m;
m.insert(map<string, int>::value_type("hello", 37));

 

5、完整代碼

.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++學習的啓蒙或許對有些初學者來講不那麼友好。不過,我之所謂選擇已這個例子由於它偏偏展示了這門語言的特色:高效。

相關文章
相關標籤/搜索