C++统计代码注释行数 & 有效代码行数 & 代码注释公共行 & 函数个数

问题来源,在14年的暑假的一次小项目当中遇到了一个这样的问题,要求统计C++代码的注释行数,有效代码行数,代码注释公共行数,以及函数个数。

下面稍微解释一下问题,

1)注释行数:指有注释的行,包括有代码和注释的公共行(如:3,4,15,22...)

2)有效代码行:指有代码的行,包括有代码和注释的公共行(如:1,4,11,15,25....)

3)代码注释公共行:指又有代码又有注释的行(如:4,15...)

4)函数个数:这个不用说明了吧。

以下为注释情况展示代码:

 1 #include <stdio.h>
 2
 3 //follow is a common line
 4 void swap(char *p/* = NULL */)
 5 {
 6     printf("this is a function /*is not comments*/");
 7 }
 8
 9 int main(void)
10 {
11     int a = 10;
12     int b;
13     char *p = NULL;
14
15     swap(p);  //common line
16     if (10 == a)
17     {
18         printf("is not function;//is not comments");
19     }
20     //pure comments/*no use*/
21
22     /*a = 5;
23     printf("not use\n");*/
24
25     b = 3;/*i‘m a comment*/ a = 5; /*comments line
26     pure //comments line;"*/......"look there*/
27     printf("test \" escape char");
28     //and the follow,maybe affect the count of function
29     if (*p == ‘{‘)
30     {
31         printf("the ‘{‘ is a question\n");
32     }
33     //
34
35     return 0;
36 }

上面的这个代码片段,已经基本上展示了各种注释可能出现的情况,接着我们来分析一下注释出现的位置:

一、“//”双斜杠注释

1)可能出现在行头部,如:第3行;

2)可能出现在行末尾,如:第15行;

注意:第18行,第26行。第18行中,//位于双引号中,注释失效;第26行中,//位于/**/注释中,//失效。

二、“/**/”斜杠星注释

1)可能出现在函数参数里,如:第4行;

2)可能注释一个段落,如:22,23行;

3)也可能出现在代码中部,如25,26行那样的复杂注释;

注意:第20行,第26行。第20行,/**/位于//注释中,失效。第26行,有一个*/位于“”中,*/失效。

好了,位置分析完毕,下面分析一下如何设计算法:

三、具体算法设计思路

1)解决文件读取

这里我们用c++文件读取,每次读取一行,将读取结果放到string变量里面,这样string变量尾部自动为‘\0‘。我们用于判断行尾部。

2)双引号问题

由于双引号里面的内容都是无效的,所以我们可以直接来个过滤双引号里面的内容。(具体实现见代码)

3)单引号问题

上面的展示代码里面也看到了,单引号里面的内容(如:if (ch == ‘{‘))可能会影响函数个数的统计,所以我们需要过滤单引号。

4)空行

这个最简单,如果string为空就是空行。包括(\t\n\r‘ ‘等等,无效字符,都算空行)。

5)“//”注释

这个较为简单,遇到//就可以进行统计,同时该行也不需要继续遍历了,直接break;然后读取下一行。

6)“/**/”注释

较麻烦,我们这里用到了代码标记,注释标记,同时还设置了当遍历到行最尾部的时候,才进行行数统计,这样避免了一行被统计多次。(具体实现见代码)

7)函数个数

首先说一下统计思路,我们统计函数的时候,只是以大括号({})为统计标记。用栈来表示,遇到左括号,入栈;遇到右括号,弹出一个左括号。知道弹到栈空,函数个数+1,

这样的话,就实现了只保留最外层那对{},里层的括号全部抵销。我们又想了一下,简化了一下,不用栈,直接用一个变量来表示括号个数,遇到左括号,++top;遇到右括号--top,直到top==0,也就相当于栈空,函数个数+1。

其实如下代码的函数个数统计还有问题:

示例:对于类、结构体、枚举体、全局数组,会被统计为一个函数。也就是说,那些在函数体外面的,但是又带有大括号({})的代码,都会被识别为函数。

以下为实现代码:

  1 #include <iostream>
  2 #include <fstream>
  3 #include <string>
  4 using namespace std;
  5
  6 int main(void)
  7 {
  8     string line="";
  9     ifstream ifs;
 10     ifs.open("Test.cpp");
 11     if (!ifs)
 12     {
 13         cout<<"文件打开失败"<<endl;
 14         exit(0);
 15     }
 16     //////////////////////////////////////////////
 17     //标记:双引号 斜杠星   函数      代码        注释
 18     int bSyh = 0, bXgx = 0, bHs = -1, bCode = 0, bZs = 0;
 19     //   ""        ‘‘        //     /*        {}
 20     /////////////////////////////////////////////
 21     //个数:空行  注释    代码      公共     函数
 22     int i,nKh = 0, nZs = 0, nDm = 0, nGg = 0, nHs = 0;
 23     //
 24     while (!ifs.eof())
 25     {
 26         i = 0;
 27         getline(ifs,line);    //读取一行文件
 28         bCode = 0;            //该行没有代码
 29         bZs = 0;              //该行没有注释
 30         if (bXgx)             //bXgx 斜杠星注释标记
 31             bZs = 1;          //该行有注释
 32         //过滤无效符号
 33         while (line[i] == ‘ ‘ || line[i] == ‘\t‘ || line[i] == ‘\r‘ || line[i] == ‘\n‘)
 34         {
 35             ++i;
 36         }
 37         //“以下为空行统计区域:开始”
 38         if (!bXgx && line[i] == ‘\0‘)  //空行
 39         {
 40             ++nKh;
 41             continue;
 42         }
 43         //“空行统计:结束”
 44         while (1)
 45         {
 46             //第一次遇到双引号              引号为非转义字符(\")
 47             if (!bSyh && line[i] == ‘\"‘ && ((i > 0 && line[i-1] != ‘\\‘) || (i == 0)))
 48             {
 49                 ++i;
 50                 bSyh = 1;
 51                 continue;
 52             }
 53             //“正在进行双引号屏蔽....”
 54             if (bSyh)
 55             {
 56                 //“ \”结束”
 57                 if (line[i] == ‘\"‘ && ((i > 0 && line[i-1] != ‘\\‘) || (i == 0)))
 58                 {
 59                     bSyh = 0;
 60                 }
 61                 else if (line[i] == ‘\0‘)  //行末尾
 62                 {
 63                     if (bZs)
 64                         ++nZs;
 65                     if (bCode)
 66                         ++nDm;
 67                     if (bZs && bCode)
 68                         ++nGg;
 69                     break;
 70                 }
 71                 ++i;
 72                 continue;
 73             }
 74             //遇到单引号(避免‘{‘,‘}‘),且非转义字符\‘,连续跳过3个(第二个‘后位置)
 75             if (line[i] == ‘\‘‘ && ((i > 0 && line[i-1] != ‘\\‘) || (i == 0)))
 76             {
 77                 i += 3;
 78                 continue;
 79             }
 80             //“//注释行”
 81             if (!bXgx && line[i] == ‘/‘ && line[i+1] == ‘/‘)
 82             {
 83                 if (bCode)     //“前有代码,混合注释行”
 84                 {
 85                     ++nZs;     //注释
 86                     ++nDm;     //代码
 87                     ++nGg;     //公共
 88                 }
 89                 else          //纯注释行
 90                 {
 91                     ++nZs;
 92                 }
 93                 break;  //跳出当前行(即,内while循环),“//”后代码不做判断
 94             }
 95             //“/*注释开始”
 96             if (!bXgx && line[i] == ‘/‘ && line[i+1] == ‘*‘)
 97             {
 98                 i += 2;        //跳过/*符号
 99                 bXgx = 1;      //标记“/*”开始
100                 bZs = 1;       //“发现注释”
101                 continue;
102             }
103             //“正在进行多行注释....”
104             if (bXgx)
105             {
106                 //“*/注释结束”
107                 if (line[i] == ‘*‘ && line[i+1] == ‘/‘)
108                 {
109                     ++i;     //“跳过*/”注意后有一个 ++i;
110                     bXgx = 0;
111                 }
112                 else if (line[i] == ‘\0‘)  //行末尾
113                 {
114                     if (bCode)       //注释前有代码,即“混合行”
115                     {
116                         ++nDm;
117                         ++nZs;
118                         ++nGg;
119                     }
120                     else
121                     {
122                         ++nZs;       //“纯注释”
123                     }
124                     break;
125                 }
126                 ++i;
127                 continue;
128             }
129             if (line[i] == ‘\0‘)
130             {
131                 if (bZs)
132                     ++nZs;
133                 if (bCode)
134                     ++nDm;
135                 if (bZs && bCode)
136                     ++nGg;
137                 break;
138             }
139             //“以下全是有效代码区域”
140             //“函数个数统计区域:开始”
141             if (line[i] == ‘{‘)      //记录函数左括号
142             {
143                 ++bHs;
144             }
145             else if (line[i] == ‘}‘) //遇到函数右括号
146             {
147                 if (bHs == 0)        //“发现一个函数”
148                     ++nHs;
149                 --bHs;
150             }
151             //“函数统计:结束”
152             ++i;
153             bCode = 1;    //能执行到这里,说明该行存在代码
154         }
155     }
156
157     cout<<"注释: "<<nZs<<endl;
158     cout<<"代码: "<<nDm<<endl;
159     cout<<"空行: "<<nKh<<endl;
160     cout<<"公共: "<<nGg<<endl;
161     cout<<"函数: "<<nHs<<endl;
162
163     return 0;
164 }

原文地址:http://www.cnblogs.com/nchar/p/3915889.html

C++统计代码注释行数 & 有效代码行数 & 代码注释公共行 & 函数个数,布布扣,bubuko.com

时间: 2024-10-12 15:58:49

C++统计代码注释行数 & 有效代码行数 & 代码注释公共行 & 函数个数的相关文章

C++代码注释行和函数个数统计

问题来源,在14年的暑假的一次小项目当中遇到了一个这样的问题,要求统计C++代码的注释行数,有效代码行数,代码注释公共行数,以及函数个数. 下面稍微解释一下问题, 1)注释行数:指有注释的行,包括有代码和注释的公共行(如:3,4,15,22...) 2)有效代码行:指有代码的行,包括有代码和注释的公共行(如:1,4,11,15,25....) 3)代码注释公共行:指又有代码又有注释的行(如:4,15...) 4)函数个数:这个不用说明了吧. 以下为注释情况展示代码: 1 #include <st

NotePad ++的妙用:添加代码行数和格式不变复制代码

NotePad ++ 不仅安装包小而且功能强大,可以支持很多语言.这里简单阐述下两个功能: 一.在代码前添加行数: 1.用NotePad ++打开一个文件,一般NotePad ++会自动识别这是什么语言的文件,关键字一般都会有特殊颜色标志.如果不能分辨出语言,也可以自动动手设置.如下图: 2.鼠标 左键选中要加行数的代码,或者鼠标定位在要加代码的开始(默认到文档都加),然后“编辑”-->“列编辑”: 打开如下对话框,并如下设置后点击确定: 则软件就自动完成了行的添加.如下图: 3.如果出现下图的

点击最后一行可以实现行自增效果的表格代码

点击最后一行可以实现行自增效果的表格代码:现在任何事务都追求效率和人性化,当然网页效果也是如此,如果一个可以编辑数据的表格,编辑到最后一行的时候,点击可以自动添加一行,这样算是一个比较人性化的效果,可以免去一丝劳顿之苦,下面分享一段这样的代码.代码如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="author" conten

GridView在不写后端代码绑定数据源且无数据的情况下显示脚注行Footer的新方法

记录一下今天解决的一个需求,GridView在页面上用SqlDataSource控件配置数据源直接绑定,不用后台代码动态绑定,然后为了方便插入数据,在参考了各位大佬的博文后,采用了在字段的脚注行里插入文本框控件,收集各列的数据,然后在后台用SqlDataSource的插入参数配置之后,直接insert方法完成新记录的入库. 理想是美好的,但现实总是有点扭曲.这个新记录插入方法在数据源有数据的时候很好使,因为只要设置了showfooter=true,脚注行就能显示.但是如果没数据的时候,脚注行就消

通过游戏学python 3.6 第一季 第三章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释 可复制直接使用 娱乐 可封装 函数

1 #猜数字--核心代码--猜测次数--随机函数和屏蔽错误代码---优化代码及注释 2 3 import random 4 number = random.randint(1,99)#设定答案(可以假设成年龄吧) 5 amount = random.randint(3,8) #设定猜测次数 6 print('本次游戏次数为',amount,'次') 7 8 count = 0 #设定初始次数 9 while count <= amount: #条件成立无限循环 10 try: 11 guess

通过游戏学python 3.6 第一季 第九章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号--锁定次数--菜单功能&#39;menufile

通过游戏学python 3.6 第一季 第九章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号--锁定次数--菜单功能'menufile 1 #猜数字--核心代码--猜测次数--随机函数和屏蔽错误代码---优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号--锁定次数--菜单功能'menufile' 2 #!usr/bin/env python 3 #-*-c

通过游戏学python 3.6 第一季 第七章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号

#猜数字--核心代码--猜测次数--随机函数和屏蔽错误代码---优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号 1 #猜数字--核心代码--猜测次数--随机函数和屏蔽错误代码---优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号 2 #!usr/bin/env python 3 #-*-coding:utf-8-*- 4 #QQ124111294 5 6 7 import random 8 number = random.rand

C# 之行存储过程操作数据库演示的代码

把开发过程比较常用的代码珍藏起来,下边代码是关于C# 之行存储过程操作数据库演示的代码,应该对码农们也有好处. public void LogRequest(string requestor, string messageBody) { using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString))

统计各个分类和标签下的文章数

作者:HelloGitHub-追梦人物 文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 在我们的博客侧边栏有分类列表和标签列表,显示博客已有的全部文章分类.现在想在分类名和标签名后显示该分类或者标签下有多少篇文章,该怎么做呢?最优雅的方式就是使用 django 的 annotate 方法. Model 回顾 回顾一下我们的 model 代码,django 博客有一个 Post 和 Category 模型,分别表示文章和分类: blog/models.py class