使用C++ STL库统计一散文中单词出现次数和行号

栏目: 编程工具 · 发布时间: 6年前

内容简介:使用C++ STL库统计一散文中单词出现次数和行号

在开发过程中经常会遇到文件处理的情形,例如统计一篇文章单词的数量、行数、出现频率最高的几个单词等等。这篇文章主要通过C++来解析一篇文章,实现每个单词(不区分大小写)出现的总次数和出现的行号的统计。

使用C++ STL库统计一散文中单词出现次数和行号

1 演示程序

文件处理能比较好地考验对开发语言基础技能的掌握能力,因为这需要去考虑数据的读取、数据的存储方式、数据的处理等等,可能不同的处理方法会得到不同的效率和结果。

下面的代码主要是使用C++的STL库解析一篇英文散文(网上看到不错就wget下来了),涉及的编程基本点如下:

1、STL容器中的map和vector容器;
2、ifstream库文件流的操作;
3、string的分割查找find、获取子串substr、去除非法字符等待;
4、c++中的基本知识点:构造函数(包括常量的初始化)、引用、对象的构造和析构等等。

文章内容如上图所示,下面直接呈上代码:

/** 
 * @FileName    stl_apply_readfile_1.cpp
 * @Describe    A simple example for using c++ STL to calculate words and line numbers in an article.
 * @Author      vfhky 2017-04-16 16:44 https://typecodes.com/cseries/stlcalcarticlewordlines1.html
 * @Compile     g++ stl_apply_readfile_1.cpp -o stl_apply_readfile_1
 */
#include <iostream>
#include <map>
#include <vector>
#include <fstream>
#include <algorithm>
#include <string>
#include <assert.h>
#include <string.h>
using namespace std;


class CFileHandle
{
public:
    CFileHandle( const string &s_file_name ) : s_m_file_name(s_file_name)
    {
        i_m_line_number = 0;
    }

    //读取每行的数据,然后进行处理
    void ReadFile( const string &s_file_name )
    {
        ifstream inFile;

        //以二进制可读的方式打开文件,也可以使用: inFile.open( s_file_name.data() );
        inFile.open( s_file_name.c_str(), ios::in | ios::binary );

        //Checks if the file stream has an associated file.
        assert( inFile.is_open() );

        //每一行的数据
        string s_line_buf;

        //读取一行内容    getline( inFile, s_line_buf )
        while( getline( inFile, s_line_buf, inFile.widen('\n') ) )
        {
            ++i_m_line_number;

            //统一转换成大写:也可以使用 transform( s_line_buf.begin(), s_line_buf.end(), s_line_buf.begin(), ::toupper );
            transform( s_line_buf.begin(), s_line_buf.end(), s_line_buf.begin(), (int (*)(int))toupper );

            //开始数据处理
            HandleLine( s_line_buf );
        }

        //关闭文件流
        inFile.close();
    }

    //对每行的数据进行解析
    void HandleLine( const string &s_line_buf )
    {
        string s_word_buf;
        int i_start=0, i_last=s_line_buf.size();
        //std::size_t i_split_pos;
        int i_split_pos = 0;

        while( i_start < i_last )
        {
            i_split_pos = s_line_buf.find( ' ', i_start );
            string s_word;

            //if( i_split_pos == std::string::npos )
            if( i_split_pos == -1 )
            {
                s_word = s_line_buf.substr( i_start, i_last );
                HandleUnkind( s_word );
                HandleWord( s_word );
                break;
            }
            /**
                避免空格,也可以使用下面这两行来去掉行首和行尾的空格
                s_line_buf.erase( 0, s_line_buf.find_first_not_of(" ") );
                s_line_buf.erase( s_line_buf.find_last_not_of(" ") + 1 );
             */
            else if( i_start != i_split_pos )
            {
                s_word = s_line_buf.substr( i_start, i_split_pos-i_start );
                HandleUnkind( s_word );
                HandleWord( s_word );
                i_start = i_split_pos + 1;
            }
            //对于行首的空格不进行处理
            else
            {
                i_start = i_split_pos + 1;
            }
        }
    }

    //去除每个单词可能包含的非字符(除0~9和A~Z外的数据)
    void HandleUnkind( string &s_word_buf )
    {
        assert( s_word_buf.size() );

        //char c_word_buf[s_word_buf.size()+1]; 在vs中会报错:error C2131: 表达式的计算结果不是常数
        char *c_word_buf = new char[s_word_buf.size()+1]();

        unsigned int j = 0;
        for( unsigned int i=0; i<s_word_buf.size(); ++i )
        {
            if( ( s_word_buf[i] >= 0x30 && s_word_buf[i] <= 0x39 ) || ( s_word_buf[i] >= 0x41 && s_word_buf[i] <= 0x5A ) )
            {
                c_word_buf[j++] = s_word_buf[i];
            }
        }

        s_word_buf = c_word_buf;
        delete c_word_buf; 
    }

    //对每个单词的处理
    void HandleWord( const string &s_word_buf )
    {
        map<string, vector<int> >::iterator mapit = mapobj.find( s_word_buf );

        //如果该单词不存在
        if( mapit == mapobj.end() )
        {
            vector<int> vect;
            vect.push_back( i_m_line_number );
            mapobj.insert( make_pair( s_word_buf, vect ) );
        }
        else
        {
            mapit->second.push_back( i_m_line_number );
        }
    }

    //遍历map对象
    void Traverse()
    {
        map< string, vector<int> >::iterator mapit = mapobj.begin();
        cout << "Words\t\t\t\tCounts\t\t\t\tLines" << endl;
        cout << "---------------------------------------------------------------------" << endl;
        for( ; mapit != mapobj.end(); ++mapit )
        {
            cout << mapit->first << "\t\t\t\t" << mapit->second.size() << "\t\t\t\t";
            for( vector<int>::iterator vectorit = mapit->second.begin(); vectorit != mapit->second.end(); ++vectorit )
            {
                cout << *vectorit << " ";
            }
            cout << endl;
        }
    }

    //获取文件总行数
    const unsigned int GetTotalLines() const
    {
        return i_m_line_number;
    }

private:
    map<string, vector<int> > mapobj;
    unsigned int i_m_line_number;
    const string s_m_file_name;
};


int main( int argc, char **argv )
{
    //文件所在路径
    const string s_file_name =  "STL_APPLY_READFILE_1";

    CFileHandle *pCFileHandle = new CFileHandle( s_file_name );

    //开始处理文件
    pCFileHandle->ReadFile( s_file_name );
    //打印总行数
    cout << "[" << __FILE__ << ":" << __LINE__ << "] Total Lines=[" << pCFileHandle->GetTotalLines() << "]." << endl;
    //遍历结果
    pCFileHandle->Traverse();

    delete pCFileHandle;

    return 0;
}

2 使用g++编译器进行编译并执行

使用g++或者之前写的这个Makefile文件进行编译,结果如下图所示。

使用C++ STL库统计一散文中单词出现次数和行号

接着执行程序 stl_apply_readfile_1 ,效果如下图所示(图片大小的限制只显示了一部分结果)。另外,上面C++程序中的数据处理函数 HandleUnkind 相对比较 粗略 :只简单过滤了非数字和字母的字符。这样会出现类似把 YOU'R 这样的数据处理成 YOUR 的情况,大家可以进行代码改进做更精细化的处理。

使用C++ STL库统计一散文中单词出现次数和行号


以上所述就是小编给大家介绍的《使用C++ STL库统计一散文中单词出现次数和行号》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java Web开发实例大全(基础卷)

Java Web开发实例大全(基础卷)

软件开发技术联盟 / 清华大学出版社 / 2016-1 / 128.00

《Java Web开发实例大全(基础卷)》筛选、汇集了Java Web开发从基础知识到高级应用各个层面约600个实例及源代码,每个实例按实例说明、关键技术、设计过程、详尽注释、秘笈心法的顺序进行了分析解读。全书分为6篇23章,主要内容有开发环境搭建、Java语言基础、HTML/CSS技术、JSP基础与内置对象、JavaBean技术、Servlet技术、过滤器与监听器技术、JSTL标签库、JavaS......一起来看看 《Java Web开发实例大全(基础卷)》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试