一道基础的词法解析题

新浪微博 QQ空间

原日志信息
标题:《计算单词数目的小程序-2009-05-24考试》
发布时间:5/24/2009
作者:童燕群

2009年,公司开始推行技能鉴定考试,这是我第一次参加的技能鉴定考试,那次考试最终以成绩不作为技术等级评定的依据收场。据说有的部门直接以金钱来奖励考分高者,在天涯论坛上面闹得沸沸扬扬。当年做这道题目时用完了所有考试时间,但是仍然没有调通,晚上回家后又接着奋战几个小时,重新写了这份代码。在现在看来,当时那个迫切想写代码的心情真的是难以理解。软件维护工作做多了,好像是会有这样的感觉。

直接贴代码,题目在代码头部的注释中。

/***************************************************************************/
/* 计算统计单词个数。 从命令行输入一个文件路径,程序读取文件内容,分析 */
/* 单词个数,并按照单词出现的频率从高到低逐个打印单词和出现的次数。 */
/* 规则: */
/* 1、单词以三种符号区分“,”(英文的逗号), “.”(英文的句点), */
/* “ ”(英文空格); */
/* 2、注释以“{”(英文左大括号)开始,以“}”(英文右大括号)结束, */
/* 允许注释嵌套,嵌套规则与C语言中的多行注释的嵌套 */
/* 规则相同(允许跨行嵌套)。 */
/* 如果只有左括号,而一直没有有括号,那么所有内容都认为是注释; */
/* 3、输出格式:每一行的格式为:“单词 出现次数”,从上倒下, */
/* 出现次数最多的行排在最上方,对于出现次数相同的单词, */
/* 可不排序; */
/***************************************************************************/

/* 输入输出示例:

输入文件内容:
fdasfasfdasf.dasfdasfas,fdasfsdafdsafdsa {
fdafdsafaskdj }
fdasfkdsa jfasf{
{{
{{}}}}}}
dk dka, dfaks , fd a, . fd a.
}}}
a aa a a
d d a fdas fdas fa sdf asf a fda sfas f asf asf a d af da ))) | { fda fdas {

输出:
a 8
d 3
asf 3
fdas 2
fd 2
| 1
sfas 1
sdf 1
fdasfsdafdsafdsa 1
fdasfkdsa 1
fdasfasfdasf 1
fda 1
fa 1
f 1
dka 1
dk 1
dfaks 1
dasfdasfas 1
da 1
af 1
aa 1
))) 1

/************************************************************************/

#include <string>
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <algorithm>

using std::map;
using std::string;
using std::vector;

#define MAX_PATN 260
#define MAX_LEN_OF_ONE_LINE 1200

typedef map<string, int> WordMayType;
WordMayType WordMap;

void DealWithOneLine(char* LineBuffer, bool* HasCommentInTheEnd);
void DealWithTheLineWithNoComments(char* LineBuffer);
void WordMapOutPut();

int main(int argc, char** argv)
{
if (argc != 2)
{
return 0;
}
bool HasCommentInTheEnd = false;
char LineBuffer[MAX_LEN_OF_ONE_LINE] =
{
0
};
FILE* fpr = fopen(argv[1], "r");
if (fpr == NULL)
{
return 0;
}

while (fgets(LineBuffer, MAX_LEN_OF_ONE_LINE, fpr) != NULL)
{
DealWithOneLine(LineBuffer, &HasCommentInTheEnd);
}

fclose(fpr);

// 输出map表到屏幕
WordMapOutPut();
system("pause");
return 0;
}

void DealWithOneLine(char* LineBuffer, bool* HasCommentInTheLastLineEnd)
{
if (NULL == LineBuffer)
{
return;
}
string LineBufferString(LineBuffer);
int nCommentBeginPos = (int) LineBufferString.find("{");
int nCommentEndPos = (int) LineBufferString.find("}");
if (nCommentEndPos == -1 &&
nCommentBeginPos == -1 &&
!*HasCommentInTheLastLineEnd)
{
// ,
// ,
//那么本行全部有效
DealWithTheLineWithNoComments(LineBuffer);
return;
}
else if (nCommentEndPos == -1 &&
nCommentBeginPos == -1 &&
*HasCommentInTheLastLineEnd)
{
//{,
// ,
//但本行没有任何注释符,那么退出,处理下一行。
return;
}
else if (nCommentEndPos == -1 &&
nCommentBeginPos != -1 &&
!*HasCommentInTheLastLineEnd)
{
// ,
//{,
//需要分两段来处理
//处理前半段
LineBuffer[nCommentBeginPos] = '\0';
DealWithTheLineWithNoComments(LineBuffer);
//处理后半段
*HasCommentInTheLastLineEnd = true;
DealWithOneLine(LineBuffer + nCommentEndPos + 1,
HasCommentInTheLastLineEnd);
}
else if (nCommentEndPos == -1 &&
nCommentBeginPos != -1 &&
*HasCommentInTheLastLineEnd)
{
//{,
//{,
//只递归处理后半段。
*HasCommentInTheLastLineEnd = true;
DealWithOneLine(LineBuffer + nCommentBeginPos + 1,
HasCommentInTheLastLineEnd);
}
else if (nCommentEndPos != -1 &&
nCommentBeginPos == -1 &&
!*HasCommentInTheLastLineEnd)
{
// ,
//},
//将饭括号去掉后继续递归处理
*HasCommentInTheLastLineEnd = false;
LineBuffer[nCommentEndPos] = ' ';
DealWithOneLine(LineBuffer, HasCommentInTheLastLineEnd);
}
else if (nCommentEndPos != -1 &&
nCommentBeginPos == -1 &&
*HasCommentInTheLastLineEnd)
{
//{,
//},
//只处理后半段
*HasCommentInTheLastLineEnd = false;
DealWithOneLine(LineBuffer + nCommentEndPos + 1,
HasCommentInTheLastLineEnd);
}
else if (nCommentEndPos != -1 &&
nCommentBeginPos != -1 &&
!*HasCommentInTheLastLineEnd)
{
// ,
//但本行两个注释符都存在
//则分两种情况
if (nCommentBeginPos < nCommentEndPos)
{
// ,
//{}
//处理前半段
LineBuffer[nCommentBeginPos] = '\0';
DealWithTheLineWithNoComments(LineBuffer);
//处理后半段
*HasCommentInTheLastLineEnd = false;
DealWithOneLine(LineBuffer + nCommentEndPos + 1,
HasCommentInTheLastLineEnd);
}
else
{
// ,
//}{,
//去掉无效字符,递归处理
LineBuffer[nCommentEndPos] = ' ';
DealWithOneLine(LineBuffer, HasCommentInTheLastLineEnd);
}
}
else if (nCommentEndPos != -1 &&
nCommentBeginPos != -1 &&
*HasCommentInTheLastLineEnd)
{
//{,
//但本行两个注释符都存在
//则分两种情况
if (nCommentBeginPos < nCommentEndPos)
{
//{,
//{}
//处理后半段
*HasCommentInTheLastLineEnd = false;
DealWithOneLine(LineBuffer + nCommentEndPos + 1,
HasCommentInTheLastLineEnd);
}
else
{
//{,
//}{
//只处理后半段
*HasCommentInTheLastLineEnd = true;
DealWithOneLine(LineBuffer + nCommentEndPos + 1,
HasCommentInTheLastLineEnd);
}
}
}

void DealWithTheLineWithNoComments(char* LineBuffer)
{
int nLen = strlen(LineBuffer);
int nWordPosBegin = 0;
int nWordPosEnd = 0;
char cLetter = '\0';
bool IsNewWordFlag = true;
for (int i = 0; i != nLen; i++)
{
cLetter = LineBuffer[i];
if ((cLetter != ' ') &&
(cLetter != ',') &&
(cLetter != 0xA) &&
(cLetter != '.'))
{
if (IsNewWordFlag)
{
nWordPosBegin = i;
IsNewWordFlag = false;
}
}
else
{
if (!IsNewWordFlag)
{
nWordPosEnd = i;
char WordTmp[MAX_LEN_OF_ONE_LINE] =
{
0
};
strncpy(WordTmp, LineBuffer + nWordPosBegin,
nWordPosEnd - nWordPosBegin);
WordMap[WordTmp]++;
}
IsNewWordFlag = true;
}
}
}

void WordMapOutPut()
{
WordMayType::const_iterator map_it2, map_it;
map_it2 = map_it = WordMap.begin();
while (map_it != WordMap.end())
{
int nValueTmp = 0;
for (; map_it != WordMap.end(); map_it++)
{
if (nValueTmp <= map_it->second)
{
nValueTmp = map_it->second;
map_it2 = map_it;
}
}
printf("%s %d\n", map_it2->first.c_str(), map_it2->second);
WordMap.erase(map_it2->first.c_str());
map_it2 = map_it = WordMap.begin();
}
}

新浪微博 QQ空间

| 1 分2 分3 分4 分5 分 (4.86- 7票) Loading ... Loading ... | 这篇文章归档在:C/C++, 算法数据结构, 职业发展 | 标签: , . | 永久链接:链接 | 评论(0) |

评论

邮箱地址不会被泄露, 标记为 * 的项目必填。

8 - 2 = *



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <img alt="" src="" class=""> <pre class=""> <q cite=""> <s> <strike> <strong>

返回顶部