>>> import sys, platform >>> print '%s %s, Python %s' %(platform.system(), platform.release(), platform.python_version()) Windows XP, Python 2.7.11 >>> sys.version '2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit (Intel)]'
import os, sys rawCountInfo = [0, 0, 0, 0, 0] detailCountInfo = []
def CalcLinesCh(line, isBlockComment):
lineType, lineLen = 0, len(line)
if not lineLen:
return lineType
line = line + '\n' #添加一个字符防止iChar+1时越界
iChar, isLineComment = 0, False
while iChar < lineLen:
if line[iChar] == ' ' or line[iChar] == '\t': #空白字符
iChar += 1; continue
elif line[iChar] == '/' and line[iChar+1] == '/': #行注释
isLineComment = True
lineType |= 2; iChar += 1 #跳过'/'
elif line[iChar] == '/' and line[iChar+1] == '*': #块注释开始符
isBlockComment[0] = True
lineType |= 2; iChar += 1
elif line[iChar] == '*' and line[iChar+1] == '/': #块注释结束符
isBlockComment[0] = False
lineType |= 2; iChar += 1
else:
if isLineComment or isBlockComment[0]:
lineType |= 2
else:
lineType |= 1
iChar += 1
return lineType #Bitmap:0空行,1代码,2注释,3代码和注释
def CalcLinesPy(line, isBlockComment):
#isBlockComment[single quotes, double quotes]
lineType, lineLen = 0, len(line)
if not lineLen:
return lineType
line = line + '\n\n' #添加两个字符防止iChar+2时越界
iChar, isLineComment = 0, False
while iChar < lineLen:
if line[iChar] == ' ' or line[iChar] == '\t': #空白字符
iChar += 1; continue
elif line[iChar] == '#': #行注释
isLineComment = True
lineType |= 2
elif line[iChar:iChar+3] == "'''": #单引号块注释
if isBlockComment[0] or isBlockComment[1]:
isBlockComment[0] = False
else:
isBlockComment[0] = True
lineType |= 2; iChar += 2
elif line[iChar:iChar+3] == '"""': #双引号块注释
if isBlockComment[0] or isBlockComment[1]:
isBlockComment[1] = False
else:
isBlockComment[1] = True
lineType |= 2; iChar += 2
else:
if isLineComment or isBlockComment[0] or isBlockComment[1]:
lineType |= 2
else:
lineType |= 1
iChar += 1
return lineType #Bitmap:0空行,1代码,2注释,3代码和注释
from ctypes import c_uint, c_ubyte, CDLL
CFuncObj = None
def LoadCExtLib():
try:
global CFuncObj
CFuncObj = CDLL('CalcLines.dll')
except Exception: #不捕获系统退出(SystemExit)和键盘中断(KeyboardInterrupt)异常
pass
def CalcLines(fileType, line, isBlockComment):
try:
#不可将CDLL('CalcLines.dll')放于本函数内,否则可能严重拖慢执行速度
bCmmtArr = (c_ubyte * len(isBlockComment))(*isBlockComment)
CFuncObj.CalcLinesCh.restype = c_uint
if fileType is 'ch': #is(同一性运算符)判断对象标识(id)是否相同,较==更快
lineType = CFuncObj.CalcLinesCh(line, bCmmtArr)
else:
lineType = CFuncObj.CalcLinesPy(line, bCmmtArr)
isBlockComment[0] = True if bCmmtArr[0] else False
isBlockComment[1] = True if bCmmtArr[1] else False
#不能采用以下写法,否则本函数返回后isBlockComment列表内容仍为原值
#isBlockComment = [True if i else False for i in bCmmtArr]
except Exception, e:
#print e
if fileType is 'ch':
lineType = CalcLinesCh(line, isBlockComment)
else:
lineType = CalcLinesPy(line, isBlockComment)
return lineType
from cffi import FFI
CFuncObj, ffiBuilder = None, FFI()
def LoadCExtLib():
try:
global CFuncObj
ffiBuilder.cdef('''
unsigned int CalcLinesCh(char *line, unsigned char isBlockComment[2]);
unsigned int CalcLinesPy(char *line, unsigned char isBlockComment[2]);
''')
CFuncObj = ffiBuilder.dlopen('CalcLines.dll')
except Exception: #不捕获系统退出(SystemExit)和键盘中断(KeyboardInterrupt)异常
pass
def CalcLines(fileType, line, isBlockComment):
try:
bCmmtArr = ffiBuilder.new('unsigned char[2]', isBlockComment)
if fileType is 'ch': #is(同一性运算符)判断对象标识(id)是否相同,较==更快
lineType = CFuncObj.CalcLinesCh(line, bCmmtArr)
else:
lineType = CFuncObj.CalcLinesPy(line, bCmmtArr)
isBlockComment[0] = True if bCmmtArr[0] else False
isBlockComment[1] = True if bCmmtArr[1] else False
#不能采用以下写法,否则本函数返回后isBlockComment列表内容仍为原值
#isBlockComment = [True if i else False for i in bCmmtArr]
except Exception, e:
#print e
if fileType is 'ch':
lineType = CalcLinesCh(line, isBlockComment)
else:
lineType = CalcLinesPy(line, isBlockComment)
return lineType
def SafeDiv(dividend, divisor):
if divisor: return float(dividend)/divisor
elif dividend: return -1
else: return 0
gProcFileNum = 0
def CountFileLines(filePath, isRawReport=True, isShortName=False):
fileExt = os.path.splitext(filePath)
if fileExt[1] == '.c' or fileExt[1] == '.h':
fileType = 'ch'
elif fileExt[1] == '.py': #==(比较运算符)判断对象值(value)是否相同
fileType = 'py'
else:
return
global gProcFileNum; gProcFileNum += 1
sys.stderr.write('%d files processed...\r'%gProcFileNum)
isBlockComment = [False]*2 #或定义为全局变量,以保存上次值
lineCountInfo = [0]*5 #[代码总行数, 代码行数, 注释行数, 空白行数, 注释率]
with open(filePath, 'r') as file:
for line in file:
lineType = CalcLines(fileType, line.strip(), isBlockComment)
lineCountInfo[0] += 1
if lineType == 0: lineCountInfo[3] += 1
elif lineType == 1: lineCountInfo[1] += 1
elif lineType == 2: lineCountInfo[2] += 1
elif lineType == 3: lineCountInfo[1] += 1; lineCountInfo[2] += 1
else:
assert False, 'Unexpected lineType: %d(0~3)!' %lineType
if isRawReport:
global rawCountInfo
rawCountInfo[:-1] = [x+y for x,y in zip(rawCountInfo[:-1], lineCountInfo[:-1])]
rawCountInfo[-1] += 1
elif isShortName:
lineCountInfo[4] = SafeDiv(lineCountInfo[2], lineCountInfo[2]+lineCountInfo[1])
detailCountInfo.append([os.path.basename(filePath), lineCountInfo])
else:
lineCountInfo[4] = SafeDiv(lineCountInfo[2], lineCountInfo[2]+lineCountInfo[1])
detailCountInfo.append([filePath, lineCountInfo])
SORT_ORDER = (lambda x:x[0], False)
def SetSortArg(sortArg=None):
global SORT_ORDER
if not sortArg:
return
if any(s in sortArg for s in ('file', '0')): #条件宽松些
#if sortArg in ('rfile', 'file', 'r0', '0'):
keyFunc = lambda x:x[1][0]
elif any(s in sortArg for s in ('code', '1')):
keyFunc = lambda x:x[1][1]
elif any(s in sortArg for s in ('cmmt', '2')):
keyFunc = lambda x:x[1][2]
elif any(s in sortArg for s in ('blan', '3')):
keyFunc = lambda x:x[1][3]
elif any(s in sortArg for s in ('ctpr', '4')):
keyFunc = lambda x:x[1][4]
elif any(s in sortArg for s in ('name', '5')):
keyFunc = lambda x:x[0]
else: #因argparse内已限制排序参数范围,此处也可用assert
print >>sys.stderr, 'Unsupported sort order(%s)!' %sortArg
return
isReverse = sortArg[0]=='r' #False:升序(ascending); True:降序(decending)
SORT_ORDER = (keyFunc, isReverse)
def ReportCounterInfo(isRawReport=True, stream=sys.stdout):
#代码注释率 = 注释行 / (注释行+有效代码行)
print >>stream, 'FileLines CodeLines CommentLines BlankLines CommentPercent %s'\
%(not isRawReport and 'FileName' or '')
if isRawReport:
print >>stream, '%-11d%-11d%-14d%-12d%-16.2f<Total:%d Code Files>' %(rawCountInfo[0],\
rawCountInfo[1], rawCountInfo[2], rawCountInfo[3], \
SafeDiv(rawCountInfo[2], rawCountInfo[2]+rawCountInfo[1]), rawCountInfo[4])
return
total = [0, 0, 0, 0]
#对detailCountInfo排序。缺省按第一列元素(文件名)升序排序,以提高输出可读性。
detailCountInfo.sort(key=SORT_ORDER[0], reverse=SORT_ORDER[1])
for item in detailCountInfo:
print >>stream, '%-11d%-11d%-14d%-12d%-16.2f%s' %(item[1][0], item[1][1], item[1][2], \
item[1][3], item[1][4], item[0])
total[0] += item[1][0]; total[1] += item[1][1]
total[2] += item[1][2]; total[3] += item[1][3]
print >>stream, '-' * 90 #输出90个负号(minus)或连字号(hyphen)
print >>stream, '%-11d%-11d%-14d%-12d%-16.2f<Total:%d Code Files>' \
%(total[0], total[1], total[2], total[3], \
SafeDiv(total[2], total[2]+total[1]), len(detailCountInfo))
def ParseTargetList(targetList): fileList, dirList = [], [] if targetList == []: targetList.append(os.getcwd()) for item in targetList: if os.path.isfile(item): fileList.append(os.path.abspath(item)) elif os.path.isdir(item): dirList.append(os.path.abspath(item)) else: print >>sys.stderr, "'%s' is neither a file nor a directory!" %item return [fileList, dirList]
def CountDir(dirList, isKeep=False, isRawReport=True, isShortName=False):
for dir in dirList:
if isKeep:
for file in os.listdir(dir):
CountFileLines(os.path.join(dir, file), isRawReport, isShortName)
else:
for root, dirs, files in os.walk(dir):
for file in files:
CountFileLines(os.path.join(root, file), isRawReport, isShortName)
def CountFile(fileList, isRawReport=True, isShortName=False):
for file in fileList:
CountFileLines(file, isRawReport, isShortName)
def LineCounter(isKeep=False, isRawReport=True, isShortName=False, targetList=[]):
fileList, dirList = ParseTargetList(targetList)
if fileList != []:
CountFile(fileList, isRawReport, isShortName)
if dirList != []:
CountDir(dirList, isKeep, isRawReport, isShortName)
import argparse
def ParseCmdArgs(argv=sys.argv):
parser = argparse.ArgumentParser(usage='%(prog)s [options] target',
description='Count lines in code files.')
parser.add_argument('target', nargs='*',
help='space-separated list of directories AND/OR files')
parser.add_argument('-k', '--keep', action='store_true',
help='do not walk down subdirectories')
parser.add_argument('-d', '--detail', action='store_true',
help='report counting result in detail')
parser.add_argument('-b', '--basename', action='store_true',
help='do not show file\'s full path')
## sortWords = ['0', '1', '2', '3', '4', '5', 'file', 'code', 'cmmt', 'blan', 'ctpr', 'name']
## parser.add_argument('-s', '--sort',
## choices=[x+y for x in ['','r'] for y in sortWords],
## help='sort order: {0,1,2,3,4,5} or {file,code,cmmt,blan,ctpr,name},' \
## "prefix 'r' means sorting in reverse order")
parser.add_argument('-s', '--sort',
help='sort order: {0,1,2,3,4,5} or {file,code,cmmt,blan,ctpr,name}, ' \
"prefix 'r' means sorting in reverse order")
parser.add_argument('-o', '--out',
help='save counting result in OUT')
parser.add_argument('-c', '--cache', action='store_true',
help='use cache to count faster(unreliable when files are modified)')
parser.add_argument('-v', '--version', action='version',
version='%(prog)s 3.0 by xywang')
args = parser.parse_args()
return (args.keep, args.detail, args.basename, args.sort, args.out, args.cache, args.target)
CACHE_FILE = 'Counter.dump' CACHE_DUMPER, CACHE_GEN = None, None from json import dump, JSONDecoder def CounterDump(data): global CACHE_DUMPER if CACHE_DUMPER == None: CACHE_DUMPER = open(CACHE_FILE, 'w') dump(data, CACHE_DUMPER) def ParseJson(jsonData): endPos = 0 while True: jsonData = jsonData[endPos:].lstrip() try: pyObj, endPos = JSONDecoder().raw_decode(jsonData) yield pyObj except ValueError: break def CounterLoad(): global CACHE_GEN if CACHE_GEN == None: CACHE_GEN = ParseJson(open(CACHE_FILE, 'r').read()) try: return next(CACHE_GEN) except StopIteration, e: return [] def shouldUseCache(keep, detail, basename, cache, target): if not cache: #未指定启用缓存 return False try: (_keep, _detail, _basename, _target) = CounterLoad() except (IOError, EOFError, ValueError): #缓存文件不存在或内容为空或不合法 return False if keep == _keep and detail == _detail and basename == _basename \ and sorted(target) == sorted(_target): return True else: return False
def main(): global gIsStdout, rawCountInfo, detailCountInfo (keep, detail, basename, sort, out, cache, target) = ParseCmdArgs() stream = sys.stdout if not out else open(out, 'w') SetSortArg(sort); LoadCExtLib() cacheUsed = shouldUseCache(keep, detail, basename, cache, target) if cacheUsed: try: (rawCountInfo, detailCountInfo) = CounterLoad() except (EOFError, ValueError), e: #不太可能出现 print >>sys.stderr, 'Unexpected Cache Corruption(%s), Try Counting Directly.'%e LineCounter(keep, not detail, basename, target) else: LineCounter(keep, not detail, basename, target) ReportCounterInfo(not detail, stream) CounterDump((keep, detail, basename, target)) CounterDump((rawCountInfo, detailCountInfo))
if __name__ == '__main__': from time import clock startTime = clock() main() endTime = clock() print >>sys.stderr, 'Time Elasped: %.2f sec.' %(endTime-startTime)
#include <stdio.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
unsigned int CalcLinesCh(char *line, unsigned char isBlockComment[2]) {
unsigned int lineType = 0;
unsigned int lineLen = strlen(line);
if(!lineLen)
return lineType;
char *expandLine = calloc(lineLen + 1/*\n*/, 1);
if(NULL == expandLine)
return lineType;
memmove(expandLine, line, lineLen);
expandLine[lineLen] = '\n'; //添加一个字符防止iChar+1时越界
unsigned int iChar = 0;
unsigned char isLineComment = FALSE;
while(iChar < lineLen) {
if(expandLine[iChar] == ' ' || expandLine[iChar] == '\t') { //空白字符
iChar += 1; continue;
}
else if(expandLine[iChar] == '/' && expandLine[iChar+1] == '/') { //行注释
isLineComment = TRUE;
lineType |= 2; iChar += 1; //跳过'/'
}
else if(expandLine[iChar] == '/' && expandLine[iChar+1] == '*') { //块注释开始符
isBlockComment[0] = TRUE;
lineType |= 2; iChar += 1;
}
else if(expandLine[iChar] == '*' && expandLine[iChar+1] == '/') { //块注释结束符
isBlockComment[0] = FALSE;
lineType |= 2; iChar += 1;
}
else {
if(isLineComment || isBlockComment[0])
lineType |= 2;
else
lineType |= 1;
}
iChar += 1;
}
free(expandLine);
return lineType; //Bitmap:0空行,1代码,2注释,3代码和注释
}
unsigned int CalcLinesPy(char *line, unsigned char isBlockComment[2]) {
//isBlockComment[single quotes, double quotes]
unsigned int lineType = 0;
unsigned int lineLen = strlen(line);
if(!lineLen)
return lineType;
char *expandLine = calloc(lineLen + 2/*\n\n*/, 1);
if(NULL == expandLine)
return lineType;
memmove(expandLine, line, lineLen);
//添加两个字符防止iChar+2时越界
expandLine[lineLen] = '\n'; expandLine[lineLen+1] = '\n';
unsigned int iChar = 0;
unsigned char isLineComment = FALSE;
while(iChar < lineLen) {
if(expandLine[iChar] == ' ' || expandLine[iChar] == '\t') { //空白字符
iChar += 1; continue;
}
else if(expandLine[iChar] == '#') { //行注释
isLineComment = TRUE;
lineType |= 2;
}
else if(expandLine[iChar] == '\'' && expandLine[iChar+1] == '\''
&& expandLine[iChar+2] == '\'') { //单引号块注释
if(isBlockComment[0] || isBlockComment[1])
isBlockComment[0] = FALSE;
else
isBlockComment[0] = TRUE;
lineType |= 2; iChar += 2;
}
else if(expandLine[iChar] == '"' && expandLine[iChar+1] == '"'
&& expandLine[iChar+2] == '"') { //双引号块注释
if(isBlockComment[0] || isBlockComment[1])
isBlockComment[1] = FALSE;
else
isBlockComment[1] = TRUE;
lineType |= 2; iChar += 2;
}
else {
if(isLineComment || isBlockComment[0] || isBlockComment[1])
lineType |= 2;
else
lineType |= 1;
}
iChar += 1;
}
free(expandLine);
return lineType; //Bitmap:0空行,1代码,2注释,3代码和注释
}
#define TRUE 1
#define FALSE 0
unsigned int CalcLinesCh(char *line, unsigned char isBlockComment[2]) {
unsigned int lineType = 0;
unsigned int iChar = 0;
unsigned char isLineComment = FALSE;
while(line[iChar] != '\0') {
if(line[iChar] == ' ' || line[iChar] == '\t') { //空白字符
iChar += 1; continue;
}
else if(line[iChar] == '/' && line[iChar+1] == '/') { //行注释
isLineComment = TRUE;
lineType |= 2; iChar += 1; //跳过'/'
}
else if(line[iChar] == '/' && line[iChar+1] == '*') { //块注释开始符
isBlockComment[0] = TRUE;
lineType |= 2; iChar += 1;
}
else if(line[iChar] == '*' && line[iChar+1] == '/') { //块注释结束符
isBlockComment[0] = FALSE;
lineType |= 2; iChar += 1;
}
else {
if(isLineComment || isBlockComment[0])
lineType |= 2;
else
lineType |= 1;
}
iChar += 1;
}
return lineType; //Bitmap:0空行,1代码,2注释,3代码和注释
}
unsigned int CalcLinesPy(char *line, unsigned char isBlockComment[2]) {
//isBlockComment[single quotes, double quotes]
unsigned int lineType = 0;
unsigned int iChar = 0;
unsigned char isLineComment = FALSE;
while(line[iChar] != '\0') {
if(line[iChar] == ' ' || line[iChar] == '\t') { //空白字符
iChar += 1; continue;
}
else if(line[iChar] == '#') { //行注释
isLineComment = TRUE;
lineType |= 2;
}
else if(line[iChar] == '\'' && line[iChar+1] == '\''
&& line[iChar+2] == '\'') { //单引号块注释
if(isBlockComment[0] || isBlockComment[1])
isBlockComment[0] = FALSE;
else
isBlockComment[0] = TRUE;
lineType |= 2; iChar += 2;
}
else if(line[iChar] == '"' && line[iChar+1] == '"'
&& line[iChar+2] == '"') { //双引号块注释
if(isBlockComment[0] || isBlockComment[1])
isBlockComment[1] = FALSE;
else
isBlockComment[1] = TRUE;
lineType |= 2; iChar += 2;
}
else {
if(isLineComment || isBlockComment[0] || isBlockComment[1])
lineType |= 2;
else
lineType |= 1;
}
iChar += 1;
}
return lineType; //Bitmap:0空行,1代码,2注释,3代码和注释
}
E:\PyTest>pypy Python 2.7.10 (b0a649e90b66, Apr 28 2016, 13:11:00) [PyPy 5.1.1 with MSC v.1500 32 bit] on win32 Type "help", "copyright", "credits" or "license" for more information. >>>> import cffi >>>> cffi.__version__ '1.6.0'
D:\pytest>CPLineCounter -d lctest -s code FileLines CodeLines CommentLines BlankLines CommentPercent FileName 6 3 4 0 0.57 D:\pytest\lctest\hard.c 27 7 15 5 0.68 D:\pytest\lctest\file27_code7_cmmt15_blank5.py 33 19 15 4 0.44 D:\pytest\lctest\line.c 44 34 3 7 0.08 D:\pytest\lctest\test.c 44 34 3 7 0.08 D:\pytest\lctest\subdir\test.c 243 162 26 60 0.14 D:\pytest\lctest\subdir\CLineCounter.py ------------------------------------------------------------------------------------------ 397 259 66 83 0.20 <Total:6 Code Files> Time Elasped: 0.04 sec.
E:\PyTest>kernprof -l -v CPLineCounter.py source -d > out.txt 140872 93736 32106 16938 0.26 <Total:82 Code Files> Wrote profile results to CPLineCounter.py.lprof Timer unit: 2.79365e-07 s Total time: 5.81981 s File: CPLineCounter.py Function: CountFileLines at line 143 Line # Hits Time Per Hit % Time Line Contents ============================================================== 143 @profile 144 def CountFileLines(filePath, isRawReport=True, isShortName=False): ... ... ... ... ... ... ... ... 162 82 7083200 86380.5 34.0 with open(filePath, 'r') as file: 163 140954 1851877 13.1 8.9 for line in file: 164 140872 6437774 45.7 30.9 lineType = CalcLines(fileType, line.strip(), isBlockComment) 165 140872 1761864 12.5 8.5 lineCountInfo[0] += 1 166 140872 1662583 11.8 8.0 if lineType == 0: lineCountInfo[3] += 1 167 123934 1499176 12.1 7.2 elif lineType == 1: lineCountInfo[1] += 1 168 32106 406931 12.7 2.0 elif lineType == 2: lineCountInfo[2] += 1 169 1908 27634 14.5 0.1 elif lineType == 3: lineCountInfo[1] += 1; lineCountInfo[2] += 1 ... ... ... ... ... ... ... ...
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有