项目源代码行数统计

最近在找工作,某公司出了这么个题:统计项目源代码行数。

为了实现跨平台用了boost,g++和vs2010编译通过。代码如下:

FileTravel.h

#pragma once
#include <string>
#include <vector>
#include <iostream>
using namespace std;

class FileTravel
{
public:
	FileTravel(void);
	FileTravel(const string& dirpath);
	~FileTravel(void);
	void SetFilterTypes(const vector<string> filtertypes);
	bool IsFilterFile(const string &filepath);
	void GetSubfiles(vector<string> & subfilepaths);
private:
	string _dirpath;				//源文件目录
	vector<string> _subfilepaths;	//源文件目录下的所有源文件路径
	vector<string> _filterTypes;	//后缀名过滤源文件类型
};

FileTravel.cpp

#include "FileTravel.h"
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

FileTravel::FileTravel(void)
	: _dirpath(NULL)
{
	_filterTypes.clear();
	_subfilepaths.clear();
}

FileTravel::~FileTravel(void)
{
}

FileTravel::FileTravel(const string& dirpath)
	: _dirpath(dirpath)
{
}

/*
	获取源文件目录下的所有代码源文件
*/
void FileTravel::GetSubfiles(vector<string> & subfilepaths)
{
	namespace fs = boost::filesystem;
	fs::path rootpath(_dirpath, fs::native);
	if(!fs::exists(rootpath))
		return;
	fs::recursive_directory_iterator endIter;

	for(fs::recursive_directory_iterator iter(rootpath); iter != endIter; iter++) {
		try{
			if(fs::is_regular_file(*iter)){
				if(IsFilterFile(iter->path().string())) {
					subfilepaths.push_back(iter->path().string());
					cout << *iter << " is a file" << std::endl;
				}
			}
		} catch ( const std::exception & ex ){
			std::cerr << ex.what() << std::endl;
			continue;
		}
	}

}

void FileTravel::SetFilterTypes(const vector<string> filtertypes)
{
	_filterTypes.clear();
	_filterTypes.assign(filtertypes.begin(),filtertypes.end());
}

/*
	过滤,判断是否是_filterTypes后缀的源文件类型
*/
bool FileTravel::IsFilterFile(const string &filepath)
{
	if(_filterTypes.size() == 0)
		return false;
	vector<string>::iterator iter = _filterTypes.begin();
	int len = filepath.length();
	while( iter != _filterTypes.end() && filepath.rfind(*iter) != len-(*iter).length()) 
		iter++;
	if(iter == _filterTypes.end())
		return false;
	return true;
}

SourceLine.h

#pragma once
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <string>
#include <vector>
using namespace boost;
using namespace std;

typedef enum linetype {
	NOTYPE_LINE,				//在空行、注释行、代码行类型之外的类型
	EMPTY_LINE,					//空行
	CODE_LINE,					//代码行
	NOTE_SINGLE_LINE,			//单行注释
	NOTE_MULTI_LINE				//多行注释
}linetype;

typedef struct  noteString{
	string singlenotestr;
	string multnote_startstr;
	string multnote_endstr;
	noteString()
	{

	}
	noteString(const noteString& notestr)
	{
		singlenotestr = notestr.singlenotestr;
		multnote_startstr = notestr.multnote_startstr;
		multnote_endstr = notestr.multnote_endstr;
	}
}noteString;

class SourceLine
{
public:
	SourceLine(void);
	SourceLine(const vector<string>& filepaths, int start, int end);
	static unsigned long GetTotallines(void);
	static unsigned long GetEmptylines(void);
	static unsigned long GetNotelines(void);
	static unsigned long GetValidCodelines(void);
	void CalculateLine(void);
	void SetNoteString(const noteString& notestr);
	~SourceLine(void);
private:
	static void incLine(linetype tp);
	linetype analyisLine(string& line);
	void calculateLine_singlefile(const string &filepath);
	void setNoteString();
	vector<string>	_filepaths;
	static unsigned long _emplines;//空行
	static unsigned long _notelines;//注释行
	static unsigned long _codelines;//有效代码行
	noteString _notestr;
};

SourceLine.cpp

#include "SourceLine.h"
#include <exception>
#include <fstream>
#include <boost/algorithm/string.hpp>
unsigned long SourceLine::_codelines = 0;
unsigned long SourceLine::_emplines = 0;
unsigned long SourceLine::_notelines = 0;
mutex emplineMutex;
mutex codelineMutex;
mutex notelineMutex;
unsigned long SourceLine::GetTotallines()
{
	unsigned long ret = GetEmptylines() + GetNotelines() + GetValidCodelines();
	return ret;
}

unsigned long SourceLine::GetEmptylines()
{
	mutex::scoped_lock lock(emplineMutex);
	return _emplines;
}

unsigned long SourceLine::GetNotelines()
{
	mutex::scoped_lock lock(notelineMutex);
	return _notelines;
}

unsigned long SourceLine::GetValidCodelines()
{
	mutex::scoped_lock lock(codelineMutex);
	return _codelines;
}

 void SourceLine::incLine(linetype tp)
 {
	 switch (tp)
	 {
	 case EMPTY_LINE:
		 {
			 mutex::scoped_lock lock(emplineMutex);
			 ++ _emplines;
		 }
		 break;	 
	 case NOTE_MULTI_LINE:
	 case NOTE_SINGLE_LINE:
		 {
			 mutex::scoped_lock lock(notelineMutex);
			 ++ _notelines;
		 }
		 break;
	 case CODE_LINE:
		 {
			 mutex::scoped_lock lock (codelineMutex);
			 ++ _codelines;
		 }
		 break;
	 default:
		 cout<<"warning: undefined line type"<<endl;
		 break;
	 }
 }

SourceLine::SourceLine()
{
	_filepaths.clear();
	setNoteString();
}

SourceLine::SourceLine(const vector<string> & filepaths, int start, int end)
{
	try
	{
		_filepaths.assign(filepaths.begin()+start, filepaths.begin()+end);
	}
	catch (const std::exception& e)
	{
		_filepaths.clear();
		cerr<<"error SourceLine construction"<<e.what()<<endl;
	}
	setNoteString();
}
SourceLine::~SourceLine()
{

}

void SourceLine::setNoteString()
{
	noteString notestr;
	notestr.singlenotestr = "//";
	notestr.multnote_startstr = "/*";
	notestr.multnote_endstr = "*/";
	_notestr = notestr;
}

void SourceLine::SetNoteString(const noteString& notestr)
{
	_notestr = notestr;
}

/*
	遍历所有源文件,计算行数
*/
void SourceLine::CalculateLine()
{
	vector<string>::iterator iter = _filepaths.begin();

	for(; iter != _filepaths.end(); iter++)
		calculateLine_singlefile(*iter);
}

/*
	计算单个源文件的各种行数
*/
void SourceLine::calculateLine_singlefile(const string &filepath)
{
	ifstream fin;
	string line;
	linetype type;
	int pos;
	fin.open(filepath.c_str(), ios::in);
	if(!fin) {
		cerr<<"error open "<<filepath<<endl;
		return;
	}

	do 
	{
		getline(fin,line);
		type = analyisLine(line);

		/*
			处理“/*xsfa*/ /*dd*”多行注释的不规范写法
		*/
		while(type == NOTE_MULTI_LINE) {
			while(!contains(line, _notestr.multnote_endstr) && !fin.eof()) {
				getline(fin,line);
				incLine(NOTE_MULTI_LINE);
			}
			if((pos = line.find(_notestr.multnote_endstr)) == string::npos) {
				cerr<<"error,invalid mutipleNote line in file."<<filepath<<endl;
				return;
			}

			line = line.substr(pos+(_notestr.multnote_endstr).length());
			trim(line);
			if(contains(line, _notestr.multnote_startstr))
				type = NOTE_MULTI_LINE;
			else 
				type = NOTYPE_LINE;
		}//while(type == NOTE_MULTI_LINE)

	} while (!fin.eof());
}

/*
	处理每一行,一行分为三种情况:
	1.空行
	2.以有效代码开头的判为代码行
	3.以//或/*开头的判为注释行   
*/
linetype SourceLine::analyisLine(string& linestr)
{
	linetype type;
	trim(linestr);
	if(0 == linestr.length())
		type = EMPTY_LINE;
	else {
		if(starts_with(linestr, _notestr.singlenotestr/*"//"*/) || starts_with(linestr, _notestr.multnote_startstr/*"/*"*/))
			type = NOTE_SINGLE_LINE;
		else
			type = CODE_LINE;
	}
	incLine(type);
	if(contains(linestr, _notestr.multnote_startstr/*"/*"*/))
		type = NOTE_MULTI_LINE;
	return type;
}

main.cpp

#include "SourceLine.h"
#include "FileTravel.h"
#include <sstream>
#include <list>

// 命令行参数:文件夹 线程数
int main(int argc, char* argv[])
{
	if(argc < 3) {
		cout<<"please intput a directory  and a number as parameters."<<endl;
		return 0;
	}
	// 1. 源文件所在的路径
	FileTravel ft(argv[1]);
	vector<string> filepaths;
	vector<string> filtertypes;

	//2. 自定义代码源文件类型,如c++的.cpp或java的.java	

	filtertypes.push_back(".h");
	filtertypes.push_back(".cpp");
	filtertypes.push_back(".hpp");
	filtertypes.push_back(".c");

	ft.SetFilterTypes(filtertypes);
	//3. 获取所有源文件路径
	ft.GetSubfiles(filepaths);
	int filecount = filepaths.size();

	if(filecount <= 0){
		cout<<"no subfiles"<<endl;
		return 0;
	}

	// 4.使用命令行参数指定的多线程数量
	stringstream ss;
	int threadnum = -1;
	ss << argv[2];
	ss >> threadnum;
	if(threadnum <= 0 )
		threadnum = 1;

	int interval = (interval = filecount/threadnum)?interval:1;
	thread_group grp;
	list<SourceLine*> listsl;
	/*
	5. 每个线程处理span个源文件
	*/
	for(int i=0,j=0; i<threadnum && j<filecount; i++) {
		int span = (i==(threadnum-1) && (filecount-j>interval))?(filecount-j):interval;
		SourceLine *sl =  new SourceLine(filepaths, j, j + span);
		/*
			此处可以通过sl->SetNoteString();设置编程语言的注释,默认是c++的注释 
		*/
		j += span;
		grp.add_thread(new boost::thread(boost::bind(&SourceLine::CalculateLine, sl)));
		listsl.push_back(sl);
	}

	grp.join_all();
	for(list<SourceLine*>::iterator listIter = listsl.begin(); listIter != listsl.end(); listIter++) {
		if(*listIter != NULL) {
			delete *listIter;
			*listIter = NULL;
		}
	}
	cout<<"empty lines:"<<SourceLine::GetEmptylines()<<endl
		<<"note lines:"<<SourceLine::GetNotelines()<<endl
		<<"code lines:"<<SourceLine::GetValidCodelines()<<endl
		<<"total lines:"<<SourceLine::GetTotallines()<<endl;	

	char c;
	cin>>c;
}

vs2010和g++编译通过。欢迎使用,发送bug.

时间: 2024-10-25 20:21:39

项目源代码行数统计的相关文章

一些著名开源项目的源代码行数统计

这些项目大多数使用C++或者C编写,使用SourceCounter-3.5.33.73工具来统计源代码数量,本来是这里下载的: https://code.google.com/p/boomworks/downloads/list 但是今天看到code.google.com即将关闭,那我还是上传一份吧: http://files.cnblogs.com/files/findumars/SourceCounter-3.5.33.73.zip -----------------------------

推荐一个代码行数统计工具cloc

代码行数统计工具cloc,它不但能统计代码行数,还能自动过滤掉代码中的注释,使用起来也很方便,强力推荐. 安装很方便,Ubuntu上直接udo apt-get install cloc就可以了 下面用mysql来做个例子吧,首先进入mysql的源代码文件夹: [email protected] ~/aproject $ cd mysql-5.6.19/ [email protected] ~/aproject/mysql-5.6.19 $ cloc . defined(%hash) is dep

代码行数统计

/** * Copyright ? 2015 All rights reserved. */ package cn.yufu.system.tools; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList;

linux文件行数统计

linux统计文件行数 文件行数统计cat employee.txt | wc -l 统计文件行数wc -l employee.txt cat employee.txt | wc -c 统计问价的字节数wc -c employee.txt cat employee.txt | wc -w 统计单词数wc -w employee.txt wc employee 同时统计文件行数.字符数.单词数 统计文件.目录.文件行数ls | wc -l 统计当前目录下的非隐含目录和非隐含文件的个数ls -a |

&lt;转&gt;统计源代码行数的一些实现方法

这个问题的思考其实对于某一种语言而言,基本都能实现,只是简单和复杂而已.而此次我讨论就是只是在linux下面使用了shell和c对源代码进行行 数的讨论.本打算是实现一个python版本的,由于python这块还不是太熟,所以就等以后熟了把这块补上. shell版 shell的强大快捷之处就在此体现出来了.我们使用find命令就直接能将目标的文件进行检索,然后我们就直接对检索出来的对象进行统计.统计 我们知道使用wc这个命令,但是我们观察一下wc的输出: 206 ./2014-03-09-jek

iOS 统计项目代码行数

最近去面试 对面的"他" 问我其中一个问题 是 "你的项目代码量是多少?" 当时的确有点蒙圈, 我可以从整个项目打包的角度考虑项目大小,我还真没想过到底我的项目代码量,于是我大概表达了一下 "我的确没从代码量考虑过项目,请教一下你们如何去统计的 如果统计项目代码量,用来干什么呢 " 然后对方回答的话我比较意外"用看的...就是看..." 大概是几个字略过去了 没有对我的疑问有任何价值性质的回应. 基于钻研精神,我后来还是问了我

Android Studio代码行数统计插件Statistics

Android Studio 是没有提提供统计代码全部行数的功能的,但是对于开发者来说,这个功能确实必备的,Statistic统计代码行数非常方便,也很详细. 1,首先肯定是将插件下载下来,下载地址:https://plugins.jetbrains.com/plugin/4509 2,下载下来之后我们将插件安装到AS上面: 进入设置界面Setting之后点击plugins,如下图所示,显示的是已经安装的插件名称,我们将下载的插件安装,点击下面按钮: 点击之后,选择已经下载好的plugins插件

Python实现代码行数统计工具

我们经常想要统计项目的代码行数,但是如果想统计功能比较完善可能就不是那么简单了, 今天我们来看一下如何用python来实现一个代码行统计工具. 思路:首先获取所有文件,然后统计每个文件中代码的行数,最后将行数相加. 实现的功能: 统计每个文件的行数: 统计总行数: 统计运行时间: 支持指定统计文件类型,排除不想统计的文件类型: 递归统计文件夹下包括子文件件下的文件的行数: 排除空行: # coding=utf-8 import os import time basedir = '/root/sc

iOS开发- 查询项目代码行数

...其实, 这功能也没什么用. 就是查询一个项目总的代码行数. 玩玩倒是可以. 方法: 在终端下面依次输入: cd 项目文件 find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.h" -or -name "*.rss" ")" -print | xargs wc -l