• C++学习笔记(一)——一个字符串分割和统计的工具(TextUtils)


    第一讲先从一个实例开始——我们需要完成一个遍历文件并统计单词出现次数的任务。分解功能:首先,按行读取文件并舍弃可能的空行。其次,将每一行都按照空格划分单词。因为可能存在标点符号,我们还需要将标点符号都删除。最后把行首或专有名词中出现的大写字母统一转换。最后将所有获取的字母放到一个关联容器中(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; 但是这会发生以下的事情,从而导致严重的性能损失:

    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));

    五、完整代码

    .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++学习的启蒙或许对有些初学者来说不那么友好。不过,我之所谓选择已这个例子因为它恰恰展现了这门语言的特点:高效。

  • 相关阅读:
    npm uninstall g 和 D什么区别
    js filter 去除对象中重复元素
    vueloader 安装指定版本 与 卸载
    [六、常用控件]9UIDatePicker日期时间选择器
    [六、常用控件]13在MKMapView地图上显示提示框
    [六、常用控件]12为MKMapView指定地理坐标
    [六、常用控件]6UITextField控件的使用
    [六、常用控件]8动作表样式警告窗口的使用
    [六、常用控件]5UISwitch开关控件的使用
    [六、常用控件]2UIButton图片按钮的使用
  • 原文地址:https://www.cnblogs.com/learnhow/p/8541823.html
Copyright © 2020-2023  润新知