C#统计C、C++及C#程序代码行数的方法
作者:北风其凉 发布时间:2022-10-04 16:19:37
本文实例讲述了C#统计C、C++及C#程序代码行数的方法。分享给大家供大家参考。具体如下:
本文中的两个函数
1)用于统计扩展名为 .h .c .cpp .cs 文件的代码行数
public static int LinesOfCode(string filename)
2)用于递归统计一个文件夹内所有扩展名为 .h .c .cpp .cs 文件的代码行数
public static int LinesOfFolder(string foldername)
一、什么样的情况算一行代码
需要注意如下几点:
1)如果一行为空,则不算作一行代码。在字符串中的空行除外,如:
Console.WriteLine(@"fasfew
fewafa");
2)Windows中的换行为\r\n,Linux中的换行为\n,因此判断隔行可以统一以\n计
(r:Carriage Return,回车;n:Linefeed,换行)
因此,判断算法采用以下步骤:
① 遇到' '、'\r'、'\t'是无效字符,直接略过
② 遇到'\n',如果该行有有效字符,则认为该行有代码,否则认为没有
③ 遇到字符'\"',则字符串开始,直到找到下一个字符'\"',中间忽略任何字符。注意字符如果找到的'\"'前有奇数个"\\",则跳过继续搜索。如果遇到'\n',则按代码行数自增1
④ 遇到形如 /*...*/ 的注释,找到'/'和'*'相连的情况,则继续找'*'和'/'相连的情况。中间若有'\n',则看注释开始前该行是否有效,有效则算一行,无效则不算
⑤ 遇到形如 //... 的注释,则看注释开始前该行是否有效,有效则算一行,无效则不算
⑥ 遍历完整个文件后,由于最后一行可能不以'\n'结尾,因此遍历完毕后最后一行有没有有效字符,有则最后一行算作一行,没有则不算
二、查看文件中的代码行数
/// <summary>
/// 检测一个C代码文件中的有效代码行数
/// </summary>
/// <param name="filename">文件名</param>
/// <returns>代码行数</returns>
public static int LinesOfCode(string filename)
{
System.IO.StreamReader sr = System.IO.File.OpenText(filename);
string s = sr.ReadToEnd();
sr.Close();
bool isLine = false; //一行中拥有有效字符时为true,该行可记入代码行数
bool isCommitLf = false; //注释/*...*/中出现至少一个折行时为true
int lines = 0; //代码行数统计
for (int i = 0; i < s.Length; i++)
{
//无效字符
if (s[i] == ' ' || s[i] == '\r' || s[i] == '\t')
{
continue;
}
//搜索到换行,若该行有有效字符
if (s[i] == '\n')
{
if (isLine)
{
lines++;
isLine = false;
}
continue;
}
//字符串,占多少行按多少行算
if (s[i] == '\"')
{
while (true)
{
i++;
//如果文件遍历完毕则强行中止
if (i >= s.Length)
{
break;
}
//再次遇到字符'"'且前方没有或有偶数个'//'时,中止循环并退出
if (s[i] == '\"')
{
int sign = 0, counter = 0;
while (true)
{
sign++;
if (i - sign < 0)
{
break;
}
else if (s[i - sign] == '\\')
{
counter++;
}
else
{
break;
}
}
if (counter % 2 == 0)
{
break;
}
}
//字符串中的换行,直接算作一行代码
if (s[i] == '\n')
{
lines++;
isLine = true;
}
}
isLine = true;
continue;
}
//遇到形如 /*...*/ 的注释
if (s[i] == '/' && i < s.Length - 1)
{
if (s[i + 1] == '*')
{
i++;
while (true)
{
i++;
//如果文件遍历完毕则强行中止
if (i >= s.Length)
{
break;
}
if (s[i] == '\n')
{
if (isCommitLf == false)
{
if (isLine == true)
{
lines++;
isLine = false;
}
isCommitLf = true;
}
}
if (s[i] == '*' && i < s.Length - 1)
{
if (s[i + 1] == '/')
{
i++;
break;
}
}
}
isCommitLf = false;
continue;
}
}
//遇到形如 // 的注释
if (s[i] == '/' && i < s.Length - 1 && s[i + 1] == '/')
{
if (isLine == true)
{
lines++;
isLine = false;
}
while (true)
{
i++;
if (i >= s.Length || s[i] == '\n')
{
break;
}
}
continue;
}
//该行有了有效字符,算作一行
isLine = true;
}
//最后一行可能没有字符'\n'结尾
if (isLine)
{
lines++;
}
return lines;
}
三、查看文件夹中所以代码文件的代码行数
/// <summary>
/// 检测一个文件夹中所有C代码的行数
/// </summary>
/// <param name="foldername">文件夹名称</param>
/// <returns>代码行数</returns>
public static int LinesOfFolder(string foldername)
{
//行数统计
int lines = 0;
//文件夹信息
System.IO.DirectoryInfo dif = new System.IO.DirectoryInfo(foldername);
//遍历文件夹中的各子文件夹
foreach (System.IO.DirectoryInfo di in dif.GetDirectories())
{
lines += LinesOfFolder(di.FullName);
}
//统计本文件夹中C语言文件代码
foreach (System.IO.FileInfo f in dif.GetFiles())
{
if (f.Extension == ".cs" || f.Extension == ".cpp" ||
f.Extension == ".c" || f.Extension == ".h")
{
lines += LinesOfCode(f.FullName);
}
}
return lines;
}
四、Main函数
输入命令 checkfile:文件名 或 checkfolder:文件夹路径 查询
static void Main(string[] args)
{
Console.WriteLine("请输入要统计的文件或文件夹");
Console.WriteLine("输入示例:checkfile:xxx / checkfolder:xxx");
try
{
string order = Console.ReadLine();
string[] temp = order.Split(':');
if (temp.Length < 2)
{
Console.WriteLine("语法错误,程序结束");
}
switch (temp[0])
{
case "checkfile":
{
int count = LinesOfCode(order.Substring(10).Trim());
Console.WriteLine("共有代码 " + count + " 行");
} break;
case "checkfolder":
{
int count = LinesOfFolder(order.Substring(12).Trim());
Console.WriteLine("共有代码 " + count + " 行");
} break;
default: Console.WriteLine("未知命令"); break;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
五、运行结果示例
希望本文所述对大家的C#程序设计有所帮助。


猜你喜欢
- 目录对象的创建创建方式对象的内存布局创建过程对象的内存分配分配方式并发安全代码优化逃逸分析的不成熟性实际的对象空间分配过程对象的访问句柄直接
- SpringBoot 集成 activiti 基础环境搭建添加依赖<dependency> <groupId&g
- 线程组我们可以把线程归属到某个线程组中,线程组可以包含多个线程以及线程组,线程和线程组组成了父子关系,是个树形结构,如下图:使用线程组可以方
- 在两个Activity跳转时,由于第二个Activity在启动时加载了较多数据,就会在启动之前出现一个短暂的黑屏时间,解决这个
- 思维导图一、为什么要学习 DialogFragment你还在用 Dialog 吗?你还在经常烦恼于屏幕翻转的时候,Dialog 的各种奇葩情
- 这里合并用到了一个itext的包。使用maven直接导入依赖即可。<dependency> <g
- 问题描述:1. 项目集成WebSocket,且打包发布tomcat时出现websocket is already in CLOSING or
- 为什么要用Flyway在日常开发中,我们经常会遇到下面的问题:自己写的SQL忘了在所有环境执行;别人写的SQL我们不能确定是否都在所有环境执
- 之前百度,google了很多,发现并没有介绍mongodb生产环境如何配置的文章, 当时想参考下都不行, 所以写篇文章,大家可以一块讨论下.
- 那些GC的默认值其实GC或者说JVM的参数非常非常的多,有控制内存使用的:有控制JIT的:有控制分代比例的,也有控制GC并发的:当然,大部分
- 基本概念servlet 关系servlet 和 servletconfig 是一对一的关系;servletconfig 作用它存储 web.
- Android通过scheme跳转界面,应该如何实现?需求通过后台返回链接地址eg: app://com.bobo.package/path
- 调用SAP WebService服务需要转换操作1、通过浏览器访问SAP WebService地址,进行验证并生成wsdl文件地址并不是可以
- 关于用户token处理到的坑当采用前后台完全分离,以微服务架构的搭建时。在搭建微服务过程中,由于每个服务都是独立的应用,这样就会造成一个统一
- 登陆的时候,发现输入账号的不同大小写竟然能够登陆。Mybatis查询代码如下<select id="selectById&q
- 1.本系统和现在有的考试系统有以下几种优势:a.和现在有的系统比较起来,本系统有科目、章节、老师、学生、班级等信息的管理,还有批阅试卷查看已
- 本文实例为大家分享了C#生成唯一订单号的具体代码,供大家参考,具体内容如下根据GUID+DateTime.Now.Ticks生产唯一订单号/
- 目录前言简介在Java上使用创建项目,并引入Jar包导入traineddata编写测试代码训练工具训练数据仓库参考前言Tesseract-O
- Android Studio下载(下文统称AS)AS最新版下载请戳:AS下载Android SDK下载SDK安装器下载SDK安装器下载请戳:
- 图片准备hole.png和slider.png为png是因为图片带有透明度。合成目标最终为前端生成两张图片:out_slider.png高度