文本文件英文单词的计数

大二课程设计中的一次小练习:
设计
 C  C++ 程序,统计英文文本文件中,出现了多少个单词,每个单词出现了几次。连续的英文字符都认为单词 (不包括数字 ) ,单词之间用空格或标点符号分隔。

单词解析部分应该可以用正则表达式的,之后会进行补充。

第一次发博文,大家多来指点下哇!


/***********************************************************************
 * File Name: WordsCount.cpp
 * Author: 夜阳		Version: 1.0
 * Created: 2012-6-18 23:28:22
 * Last Change: 2012-6-20 9:04:44
 * Discription: 统计英文文本文件中,出现了多少个单词,每个单词出现了几次
 *
 *  运行WordsCount.cpp
 *  第一步输入待检索文件名(如TUT.txt)
 *  第二步输入输出的文件名(如result.txt)
 *  检索结果保存在result.txt中
 ***********************************************************************/

#include <stdio.h>
#include "SqList.h"				// 线性表的存储与操作

int pickword ( FILE *f, char *fword );

int main()
{
    FILE *f1, *f2;

    // 指定默认文件名,用字符串保存文件名,便于操作
    const int MAX_FILENAME = 20;				// 文件名长度
    char fname1[MAX_FILENAME] = "TUT.txt";
    char fname2[MAX_FILENAME] = "result.txt";

    // 用户指定源文件名
    printf ( "请指定源文件名(不超过%d个字符):", MAX_FILENAME );
    scanf ( "%s", fname1 );

    // 用户指定输出文件名
    printf ( "请指定要输出结果的文件名(不超过%d个字符):", MAX_FILENAME );
    scanf ( "%s", fname2 );

    //打开文件
    if ( ( f1 = fopen ( fname1, "r" ) ) == NULL )	// 异常处理
    {
        printf ( "打开文件%s失败!\n", fname1 );
        return 0;
    }
    else
        printf ( "打开文件%s成功!\n", fname1 );

    SqList L;				// 建立线性表
    SqListInit ( &L );			// 初始化线性表

    char fword[MAX_CHARACTER];			// 使用fword数组保存文件中的单词
    fword[MAX_CHARACTER - 1] = '\0';
    int i = -1;				// 设置i为插入位置

    while ( !feof ( f1 ) )		// 读文件未结束
    {
        int judge = pickword ( f1, fword );			// 从f指向的文件中提取单词到fword中

        if ( -1 == judge )						// 数组越界时提示并退出
        {
            printf ( "存在单词字符长度超过数组界限\n" );
            return -1;
        }

        if ( SqListBSearch ( &L, fword, i ) )	// i返回插入位置或单词在线性表中位置
        {
            // 在线性表中找到该单词
            L.elem[i].count++;			// 单词出现次数加1
        }
        else
        {
            // 线性表中未找到该单词
            SqListInsert ( &L, i, fword );		// 在第i个位置上插入
        }
    }

    // 打开文件fname2,将内容写入
    if ( ( f2 = fopen ( fname2, "w" ) ) == NULL )	// 异常处理
    {
        printf ( "写入文件%s失败!\n", fname2 );
        return 0;
    }
    else
        printf ( "文件已写入%s!\n", fname2 );

    // 将结果写入f2指向的文件中
    SqListPrint ( f2, fname1, &L );

    // 关闭文件
    fclose ( f1 );
    fclose ( f2 );
}

int pickword ( FILE *f, char *fword )				// 从f指向的文件中提取单词到fword中
{
    char ch;									// ch储存待检测字符

    for ( int j = 0 , flag = 0 ; !feof ( f ) ; )	// 逐个对字符进行检测,flag用于标记,为0时表示单词中无字母
    {
        if ( j >= MAX_CHARACTER )				// 判断数组是否越界
        {
            return -1;
        }

        ch = fgetc ( f );							// 获取字符

        if ( ch >= 'A' && ch <= 'Z' )			// 大写字符转小写保存在fword数组中
        {
            fword[j++] = ch + 32;
            flag = 1;
        }

        if ( ( ch >= 'a' && ch <= 'z' ) )		// 小写字符保存在fword数组中
        {
            fword[j++] = ch;
            flag = 1;
        }

        if ( '-' == ch && fword[j - 1] >= 'a' && fword[j - 1] <= 'z' )	// 若单词中带连字符,将连字符保存在fword数组中
        {
            fword[j++] = ch;
        }

        if ( ! ( ( ch >= 'A' && ch <= 'Z' ) || ( ch >= 'a' && ch <= 'z' ) || '-' == ch )
                && flag == 1 )						// 过滤单词中的非字母字符
        {
            if ( fword[j - 1] == '-' )				// 排除类似于 a- 的单词
                fword[j - 1] = '\0';

            fword[j] = '\0';					// fword数组以'\0'结尾
            return 0;
        }
    }
}

/***********************************************************************
 * File Name: SqList.h
 * Author: 夜阳		Version: 1.0
 * Created: 2012-6-18 10:25:27
 * Last Change: 2012-6-19 21:36:53
 * Discription: 顺序表的初始化,建立,插入,查找,相关结果输出
 ***********************************************************************/

#include <stdio.h>
#include <malloc.h>
#include <string.h>

const int MAX_CHARACTER = 50;		// 单词最大长度定为50(TUT.txt文中最长单词为production-education-researching)

//函数结果状态代码
#define TRUE	1
#define FALSE	0
#define OK		1
#define ERROR	0
#define OVERFLOW -2

// 线性表的动态分配顺序存储结构
#define LIST_INIT_SIZE 100	// 线性表存储空间的初始分配量
#define LISTINCREMENT 10	// 线性表存储空间的分配增量

// 顺序存储结构的线性表类型
typedef struct
{
    char word[MAX_CHARACTER];		// 存储单词,不超过50个字符
    int count;			// 单词出现次数
} ElemType;
typedef struct
{
    ElemType *elem;		// 存储空间基址
    int length;			// 当前长度
    int listsize;		// 当前分配的存储容量(以sizeof(ElemType)为单位)
} SqList;

// 线性表的初始化
int SqListInit ( SqList *L )
{
    // 构造一个空的线性表L
    L->elem = ( ElemType * ) malloc ( LIST_INIT_SIZE * sizeof ( ElemType ) );

    if ( !L->elem ) return OVERFLOW;		// 存储分配失败

    L->length = 0;
    L->listsize = LIST_INIT_SIZE;
    return OK;
}

// 线性表的插入
int SqListInsert ( SqList *L, int i, char *fword )
{
    // 在顺序线性表L中第i个位置之前插入新的元素e
    // i的合法值为1≤i≤L.Length + 1
    if ( i < 0 || i > L->length )
    {
        printf ( "i的值不合法!" );
        return ERROR;	// i的值不合法
    }

    if ( L->length >= L->listsize )
    {
        // 当前存储空间已满,增加分配
        ElemType *newbase = ( ElemType * ) realloc ( L->elem,
                            ( L->listsize + LISTINCREMENT ) * sizeof ( ElemType ) );

        if ( !newbase )
            return OVERFLOW;	// 存储分配失败

        L->elem = newbase;		// 新基址
        L->listsize += LISTINCREMENT;	// 增加存储容量
    }

    ElemType *p, *q;
    q = &L->elem[i];

    for ( p = &L->elem[L->length - 1]; p >= q; p-- )	// 插入位置之后元素逐个右移
    {
        * ( p + 1 ) = *p;
    }

    strcpy ( q->word, fword );			// 复制fword中的字符到L->elem[i-1].word中
    L->elem[i].count = 1;			// 设置计数初值为1
    L->length++;						// 表长增1
    return OK;
}

// 线性表二分法查找
int SqListBSearch ( SqList *L, char *sword, int &i )
{
    if ( L->length == 0 )			// 当线性表为空时
    {
        i = 0;					// i返回单词插入位置
        return ERROR;
    }

    // 线性表不空时,在线性表L中查找元素sword,用i返回其在线性表中的位置
    int low = 0, high = L->length - 1, mid = L->length;

    while ( low <= high )
    {
        mid = ( low + high ) / 2;
        int k = strcmp ( L->elem[mid].word, sword );

        if ( k == 0 )							// 待查单词sword等于中间值,找到待查元素
        {
            i = mid;
            return OK;						// 查找成功,函数返回值为1,用i返回所查元素在线性表中的位置
        }
        else if ( k > 0 )						// 待查单词sword小于中间值,继续在前半区间进行查找
        {
            high = mid - 1;
            i = low;
        }
        else								// 待查单词sword大于中间值,继续在后半区间进行查找
        {
            low = mid + 1;
            i = high + 1;
        }
    }

    return ERROR;							// 线性表中不存在待查元素,函数返回值为0,i返回单词插入位置
}

void SqListPrint ( FILE *f, char fname[], SqList *L )
{
    fprintf ( f, "文档 %s 中总计有%d个单词\n", fname, L->length );			// 输出统计信息,L->length为单词个数
    fprintf ( f, "序号  单词                 个数\n" );

    for ( int i = 0, j = 1 ; i < L->length ; i++, j++ )					// j-序号
        fprintf ( f, "%-5d %-20s %d\n", j, L->elem[i].word, L->elem[i].count );
}

结果显示:


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值