统计代码注释行的一些问题

1. 要统计一个c文件或者cpp文件里面的注释行,空行,总行数等,首先我们遇到的问题就是打开这个文件。

ofstream: 写操作(输出)的文件类 
ifstream: 读操作(输入)的文件类

fstream: 可同时读写操作的文件类

这里我们只要读取文件里面的数据即可,所以选用ifstream.注意头文件(fstream).

然后我们也许想,我想打开指定位置的文件,应该怎么做,怎么把指定目录下的c文件和cpp文件显示出来让我们选择。这里我们就要用到一些“dos”命令了。

ifstream infile; 
system(“dir /D file\*.c*”); 
cout << “please enter a file name: “; 
char filename[50]; 
cin >> filename; 
char path[100] = “E:\VS workplace\C++ place\CTEXT\CTEXT\file\”; 
strcat_s(path, 100, filename); 
infile.open(path); 
if (!infile)

{

       cout << "open file error!" << endl;

       exit(1);

}

第一行就不用多说了,第二行就是显示当前工作路径的file文件下面的c文件和cpp文件,*是通配符。System就是调用一些dos命令用的,记得加头文件(windows.h),dir就是列出目录下面的文件,/D是dir的选项,(help dir 就可以查到)这样列出的文件更加看一些,当然你可以选其他的选项,选项后面就是文件路径了,记得路径的反斜杠要有转义字符哦,两个反斜杠。

文件名当然要我们自己输入了,所以3,4,5行就是干这个用的。6,7行是把要打开的文件名和路径连接起来。Strcat(strcat_s更安全一些,比如你连接后的字符串超过预定空间了,编译不会提示错误,只要执行时才出错,这个我也不太懂)连接两个字符串,头文件(cstring).第8行就是打开文件喽。infile.open(path),path后面还可以写上选项。

ios::in 为输入(读)而打开文件

ios::out 为输出(写)而打开文件

ios::ate 初始位置:文件尾

  ios::app 所有输出附加在文件末尾

         ios::trunc 如果文件已存在则先删除该文件

ios::binary 二进制方式

例如(infile.open(path, ios::binary)),以二进制方式打开。

后面几行就是判错了,看看是否正确打开。

(打开文件的方法当然不止我这样写,选一种自己看着顺眼的即可,比如ifstream infile(”filename”)).接下来进入我们的重点环节。

  1. 文件打开了,这次就要开始读里面的数据了。

分析:a. 要统计注释行,即出现这些符号的行,”//”,”/* */”。

  b. 要统计空行,即遇到换行符都没有一个字符。

  c. 要统计总行数,定义一个静态变量,每读取一行前,加加即可。

  d. 统计代码行。

我们注意到,那些注释符都是由两个字符组成的。

1,如果我们每次从文件中读取一个字符,那么,我们就需要一前一后标记两个字符,就要打开文件两次,定义两个指针。

2,如果我们每次读取一行,那么就不用那么麻烦,统计总行数也非常方便。但同时出现的问题就是,每次读取出来的数据要存起来,然后在里面找那些注释符号。

思考:注释出现的情况比较多,例如下面这些注释行

  1. //  xxxxxxxxx  单行行注释
  1. /* xxxxxxxxxx 单行块注释 */
  2. /* xxxxxxxxxxxxx 多行块注释
    Xxxxxxxx
    
     Vvvvvvvvvv
    

    */

  3. /* // 单行块注释里面出现行注释符号。 */
  4. /* xxxxxxxxxx

    Vvvvvvvvvvv 多行块注释出现行注释

    // ccccccc

    */

  5. xxxxxxxxxxxxxxx //vvv 前代码,后注释

8.……

首先我们看看这些情况,通过观察我们发现,我们要记录两个数据,第一是注释符本身,第二是注释符出现的位置.(一行里面,比较先出现块注释符号还是行注释符号// /* )

如果是行注释”//”在前,块注释在后面,则忽略块注释” /* ”。如果先有块注释 ” /* ”,则要忽略块注释里面的全部行注释,不予计算。

如果我们采用一个一个字符的方法读数据,我只想说“我滴神呀!,要记录的东西太麻烦了!”,好吧,咱们还是用每次读取一行的方法吧。

每次读取一行,然后在里面找相应匹配的字符,然后…… ,等等,刚才我们说啥? 匹配字符!这个……,我们可以写一个函数,然后在里面找子字符串呀! 找这些 “//, /* , */”,

同时,我们可以返回那些子字符串出现的位置,然后……几乎所有问题都解决了!好了,我们看看这个函数。

int isStr(char *s1, char *s2)

{

     int i = 0, j = 0;

     while (s1[i] != ‘\0‘)

     {

               if (s1[i] == s2[j])

               {

                        i++;

                        j++;

                        if (s2[j] == ‘\0‘)

                                 return i - j;

                        continue;

               }

               i++;

               j = 0;

     }

     return -1;

}

这个相信大家都能看懂的,不做解释了。

我们说点题外话,关于我当时读取文件内容时出现的问题。

while (!infile.eof())

     {

               infile.read(&ch, 1);

               cout << ch;

     }

看看输出结果,怎么有点不对呢?

最后一个字符数被读取了两次???????????然后我百度了一下,觉得这个解释还能说的通。

事实上,文件本身是没有文件结束符EOF的。当读取文件中最后一个有效字符后,虽然文件指针已指向空白了,但这时还不知道是否到了文件末尾,只有再读取一次文件,待读不到任何内容了,这时输入流设置eofbit位,eof的返回值才为l,而空的内容是不会被提取到变量的,故最后一次读到变量中的内容又被重复输出了。

     while (infile.read(&ch, 1))

     {

               //infile.read(&ch, 1);

               cout << ch;

     }

3.接下来就是见证奇迹的时刻了,咱们逐一分析相应的情况应该怎么做。

首先我们要定义一些变量记录这些出现的情况了,当然刚开始不可能想的那么完全,我也是需要什么然后才定义的。

下面是这个程序的大概代码:

#include<iostream>
#include<fstream>
#include<string>
#include <windows.h>
using namespace std;

char* ignoreblank(char* s)
{
    while (*s == ‘ ‘ || *s == ‘ ‘)
        ++s;
    return s;
}

int isStr(char *s1, char *s2)
{
    int i = 0, j = 0;
    while (s1[i] != ‘\0‘)
    {
        if (s1[i] == s2[j])
        {
            i++;
            j++;
            if (s2[j] == ‘\0‘)
                return i - j;
            continue;
        }
        i++;
        j = 0;
    }
    return -1;
}

void Getfile();

int main(void)
{
    Getfile();
    return 0;
}

void Getfile()
{
    ifstream infile;
    system("dir /D  file\\*.c*");
    cout << "please enter a file name: ";
    char filename[50];
    cin >> filename;
    fflush(stdin);
    char path[100] = "E:\\VS workplace\\C++ place\\CTEXT\\CTEXT\\file\\";
    strcat_s(path, 100, filename);
    infile.open(path);
    if (!infile)
    {
        cout << "open file error!" << endl;
        exit(1);
    }
    string s;
    int  count = 0;
    int commLines = 0;
    int massiveline = 0;
    int sub_commLines = 0;// 若"/*  */" 之间的//  应该减掉
    int all_comm = 0;//只有注释
    int nullcodeLines = 0;
    int AccoutStar1 = 0;// 记录 /* 的次数
    //while (infile.read(&ch, 1))
    int markslines = 0; //记录  双引号里面的注释行
    bool marksflag = true;//匹配双引号
    while (getline(infile, s))
    {
        ++count;
        int set;
        char* p;

        p = new char[s.length() + 1];
        strcpy_s(p, s.length() + 1, s.c_str());

        if (s.length() == 0)
            ++nullcodeLines;

        //if (ch == ‘ ‘ || ch == ‘  ‘)//忽略空格和tab
        char* b = ignoreblank(p);
        set = isStr(b, "//");    //根据返回值判断注释行有没有代码。set是0  则全是注释
        if (set == 0)
            ++all_comm;
        if (set != -1)
            ++commLines;

        int set2;
        set2 = isStr(p, "/*");/**/
        if (set2 != -1)
        {
            int set3;//比较先有//  还是/*
            set3 = isStr(p, "//");
            if (set3 != -1 && set3 < set2)
                continue;

            else if (set3 != -1 && set3>set2)
            {
                AccoutStar1 = 1;
                ++sub_commLines;
            }
            else
                AccoutStar1 = 1;
        }

        if (AccoutStar1 == 1 && set != -1)
            ++sub_commLines; //   这种情况应该把 //的注释记录减一  "// */   "
        if (AccoutStar1 == 1)
            ++massiveline;
        int set4;// 记录 */
        set4 = isStr(p, "*/");
        if (set4 != -1 && AccoutStar1 == 1)
        {
            AccoutStar1 = 0;
        }

        int set6;  //记录另一半双引号
        set6 = isStr(p, "\"");
        if (marksflag == false && set6 != -1 && set == -1)
        {
            marksflag = true;
            markslines = 0;
        }

        int set5;//这种情况字符串里面出现 注释
        set5 = isStr(p, "\"");

        if (set5 != -1 && set6 != -1 && marksflag == true && set == -1)
        {
            marksflag = true;
            ++markslines;
        }

        if (set5 != -1 && marksflag == true)
        {
            marksflag = false;
        }
        if (marksflag == false && set != -1 && set5>set)
            ++markslines;
        delete[] p;
    }
    cout << "总行数为: " << count << endl;
    cout << "空格行为:" << nullcodeLines << endl;
    cout << "注释行为: " << commLines + massiveline - sub_commLines - markslines;
    cout << "    (其中的块注释行个数为: " << massiveline << ")" << "    (其中只有注释的行个数为: " << all_comm << ")" << endl;
    cout << endl;
    infile.close();
}

还是直接说方法吧,上面的代码只是一些片段,仅仅提出我的一种方法而已,整个程序还是要读者自己完成的。

我们每次读取文件的一行,然后写一个函数判断是否有注释符号出现,即那些注释符是不是这一行字符串的子字符串,同时返回出现的位置。

1.空行和总行数,就不用多说了。字符串长度为0,就是空行。每次读一行,++count,就是总行数。

2.一行里面出现“//”就是注释行了,但是要注意这种情况。

“//”在“/”里面。 即 / xxxx // vvvvv / 。这时我们就不能把块注释里面的行注释再次进行计算,我们可以把在块注释里面出现的行注释次数记录下来,最后再减去。如果这些是在一行里面出现,我们一行里面要记录的东西就是,“//”,“/”,“*/”,和它们出现的位置,然后比较先出现哪个。(我们也可以定义一个标志符flag,定义时为真,即bool flag=true,当出现块注释后,flag变为假,直到出现另一半块注释符,再变为真。然后每次记录的行注释的时候,同时判断flag是否为真,比如if(flag==true && ……))

3.注释符出现在双引号里面,即当做字符串的。”xxxxxxxxxxxx // vvv /* xx”

这些情况,我们只需要记录那些符号出现的位置,然后对比,或者再定义一个标识符(bool flag1=true,当遇到引号(“ “ ”)时,flag1变为假,每次记录时,同时判断flag1即可。这时,问题来了。这样看来,要定多少标识符呀,每次判断时,括号里面要写多少东西呀。我们可以先判断一行里面出现了哪些符号,引号,行注释,块注释,然后根据情况再选择进行判断

时间: 2024-10-15 20:31:38

统计代码注释行的一些问题的相关文章

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

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

python统计代码总行数(代码行、空行、注释行)

我们在工作或学习代码的过程中,经常会想知道自己写了多少行代码,今天在项目环境写了个脚本统计了项目代码的数量. 功能: 1.统计代码总行数 2.统计空行数 3.统计注释行数 # coding=utf-8 import os #定义代码所在的目录 base_path = '/home/yhl/workspace/xtp_test' #在指定目录下统计所有的py文件,以列表形式返回 def collect_files(dir): filelist = [] for parent,dirnames,fi

统计代码行数的实用脚本

每次快到年底的时候各种的审计工作都在进行中,而最近应为部门需要统计个人写的代码有多少为此,为了方便统计就写了一个脚本用于统计代码的行数,脚本如下: #!/bin/bash #count.sh #Use Count the number of lines of code #writer jim #history #2016.12.27 if [ $# -lt 1 ];then         echo "please enter argc!"         echo "ex&

统计python文件中的代码,注释,空白对应的行数

其实代码和空白行很好统计,难点是注释行 python中的注释分为以#开头的单行注释 或者以'''开头以'''结尾 或以"""开头以"""结尾的文档注释,如: ''' hello world '''和 ''' hello world''' 思路是用is_comment记录是否存在多行注释,如果不存在,则判断当前行是否以'''开头,是则将is_comment设为True,否则进行空行.当前行注释以及代码行的判断,如果is_comment已经为True

Java关于条件判断练习--统计一个src文件下的所有.java文件内的代码行数(注释行、空白行不统计在内)

要求:统计一个src文件下的所有.java文件内的代码行数(注释行.空白行不统计在内) 分析:先封装一个静态方法用于统计确定的.java文件的有效代码行数.使用字符缓冲流读取文件,首先判断是否是块注释开头,接着判断是否是块注释结尾,再判断是否是单行注释或者空白行,若都不是则是有效代码,统计行数+1. 对于文件夹路径,采用递归的方法判断子条目是文件还是文件夹,是文件就调用静态统计方法.源代码: public class CalculateRow { public static void main(

java简单统计.java文件中的有效代码行,空行,注释行

package regxdemo; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class CountFile { /** * @param args */ static int cntCode=0, cntNode=0, cntSpace

python 脚本(获取指定文件夹、指定文件格式、的代码行数、注释行数)

1.代码的运行结果: 获取 指定文件夹下.指定文件格式 文件的: 总代码行数.总注释行数(需指定注释格式).总空行数: 1 #coding: utf-8 2 import os, re 3 4 # 代码所在目录 5 FILE_PATH = './' 6 7 def analyze_code(codefilesource): 8 ''' 9 打开一个py文件,统计其中的代码行数,包括空行和注释 10 返回含该文件总行数,注释行数,空行数的列表 11 ''' 12 total_line = 0 13

Python 统计代码行

正在学习 Python, 做了个统计代码行的功能, 参考了网上很多前辈的帖子,添加了感觉还是比较实用的功能, 只是windows下测试了,而且代码文件编码形式是 utf-8的. 如果使用其它编码形式的话,估计修改下代码就行了. 功能特点: 是否统计空行 统计注释 设置忽略文件平 设置统计文件类型 根据不同文件类型,设置注释标签 以下,是代码: 1 # Created by Aaron <[email protected]> in 2014 2 # This code is for Python

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

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