鱼C论坛

 找回密码
 立即注册
查看: 1645|回复: 4

[已解决]请教: 第035讲 EasyGui课后测试题中的第4题,为什么我统计的Py文件代码行数不对呢?

[复制链接]
发表于 2017-7-31 08:35:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
# 第035讲 EasyGui
# 动动手 4.写一个程序统计你当前的代码量总和,并显示离十万行代码量还差多远?
# 要求1: 递归搜索各个文件夹
# 要求2:显示各个类型的源文件和源代码数量
# 要求3:显示总行数与百分比

问题: 统计py文件代码行数 总是不对,不知为什么呢?

  1. import easygui as g
  2. import os

  3. # 显示结果函数:
  4. # source_list字典中keys为扩展名,values为行数;
  5. # file_list字典中keys为扩展名,values为相应类型的文件数;
  6. def show_result(start_dir):
  7.     lines = 0
  8.     total = 0
  9.     text = ""

  10.     for i in source_list:
  11.         lines = source_list[i]  # 读取不同类型代码的行数
  12.         total += lines          # 累加到total中
  13.         text += "【%s】源文件 %d 个,源代码 %d 行\n" % (i, file_list[i], lines)
  14.         # 以上(i, file_list[i], lines)是(扩展名,文件数,该类型文件代码量)
  15.         # 如(py,10,5700)即10个py文件,总共5700行代码
  16.         
  17.     title = '统计结果'
  18.     msg = '您目前共累积编写了 %d 行代码,完成进度:%.2f %%\n离 10 万行代码还差 %d 行,请继续努力!' % (total, total/1000, 100000-total)
  19.    
  20.     g.textbox(msg, title, text)

  21. # 统计行数函数:统计文件中的行数,file_name为文件名
  22. def calc_code(file_name):
  23.     lines = 0
  24.     with open(file_name) as f:
  25.         print('正在分析文件:%s ...' % file_name)
  26.       
  27.         try:
  28.             for each_line in f:
  29.                 lines += 1
  30.         except UnicodeDecodeError:
  31.             pass # 不可避免会遇到格式不兼容的文件,这里忽略掉......
  32.     return lines


  33. # 根据指定路径搜索文件函数

  34. def search_file(start_dir) :
  35.     os.chdir(start_dir)   # 把指定路径改成工作路径,有了这行代码,后面文件操作会很简单
  36.    
  37.     for each_file in os.listdir(os.curdir) :
  38.         ext = os.path.splitext(each_file)[1]
  39.         if ext in target :
  40.             lines = calc_code(each_file) # 调用统计行数函数
  41.             # 还记得异常的用法吗?如果字典中不存,抛出 KeyError,则添加字典键
  42.             # 统计文件数
  43.             try:
  44.                 file_list[ext] += 1
  45.             except KeyError:
  46.                 file_list[ext] = 1
  47.             # 统计源代码行数
  48.             try:
  49.                 source_list[ext] += lines
  50.             except KeyError:
  51.                 source_list[ext] = lines
  52.             

  53.         # 如果路径还有文件夹,进入该文件夹继续搜索
  54.         if os.path.isdir(each_file) :
  55.             search_file(each_file) # 递归调用
  56.             os.chdir(os.pardir) # 递归调用后切记返回上一层目录(**这点很关键**)
  57.             
  58. target = ['.c', '.cpp', '.py', '.cc', '.java', '.pas', '.asm','.txt']
  59. file_list = {}     #字典file_list中 keys为扩展名,values为相应的文件数量
  60. source_list = {}   #字典source_listkeys为扩展名,values为代码行数

  61. g.msgbox("请打开您存放所有代码的文件夹......", "统计代码量")
  62. path = g.diropenbox("请选择您的代码库:",title='打开文件夹',default="C:\Program Files\Python36")

  63. search_file(path)   # 搜索文件
  64. show_result(path)   # 显示结果
复制代码


问题: 统计py文件代码行数不正确
最佳答案
2017-8-1 23:43:37
给你整了段解决文件编码问题的代码:
1,首先安装 https://pypi.python.org/pypi/chardet(3.0以上安装方法:下载.gz文件,解压后,进入chardet目录,执行 setup.py install )
2,代码修改处:
  1. #以rb读取文件返回文件的编码(用到了chardet类)
  2.         with open(file_name, 'rb') as f:
  3.             raw = f.read()
  4.             result = chardet.detect(raw)  
  5.             encoding = result['encoding']

  6.         lines = 0   
  7.         with open(file_name,encoding=encoding) as f:
  8.             print('正在分析文件:%s ...' % file_name)     
  9.             try:
  10.                 for each_line in f:
  11.                     lines += 1
  12.             except Exception as reason:
  13.                 print(str(reason)) # 读取出错显示错误信息......
  14.         print('%s -> %s' % (file_name,lines))
  15.         return lines
复制代码


3,完整代码:
  1. import easygui as g
  2. import os
  3. import chardet

  4. # 显示结果函数:
  5. # source_list字典中keys为扩展名,values为行数;
  6. # file_list字典中keys为扩展名,values为相应类型的文件数;
  7. def show_result(start_dir):
  8.     lines = 0
  9.     total = 0
  10.     text = ""

  11.     for i in source_list:
  12.         lines = source_list[i]  # 读取不同类型代码的行数
  13.         total += lines          # 累加到total中
  14.         text += "【%s】源文件 %d 个,源代码 %d 行\n" % (i, file_list[i], lines)
  15.         # 以上(i, file_list[i], lines)是(扩展名,文件数,该类型文件代码量)
  16.         # 如(py,10,5700)即10个py文件,总共5700行代码
  17.         
  18.     title = '统计结果'
  19.     msg = '您目前共累积编写了 %d 行代码,完成进度:%.2f %%\n离 10 万行代码还差 %d 行,请继续努力!' % (total, total/1000, 100000-total)
  20.    
  21.     g.textbox(msg, title, text)

  22. # 统计行数函数:统计文件中的行数,file_name为文件名
  23. def calc_code(file_name):
  24.         #以rb读取文件返回文件的编码(用到了chardet类)
  25.         with open(file_name, 'rb') as f:
  26.             raw = f.read()
  27.             result = chardet.detect(raw)  
  28.             encoding = result['encoding']

  29.         lines = 0   
  30.         with open(file_name,encoding=encoding) as f:
  31.             print('正在分析文件:%s ...' % file_name)     
  32.             try:
  33.                 for each_line in f:
  34.                     lines += 1
  35.             except Exception as reason:
  36.                 print(str(reason)) # 读取出错显示错误信息......
  37.         print('%s -> %s' % (file_name,lines))
  38.         return lines


  39. # 根据指定路径搜索文件函数

  40. def search_file(start_dir) :
  41.     os.chdir(start_dir)   # 把指定路径改成工作路径,有了这行代码,后面文件操作会很简单
  42.    
  43.     for each_file in os.listdir(os.curdir) :
  44.         ext = os.path.splitext(each_file)[1]
  45.         if ext in target :
  46.             lines = calc_code(each_file) # 调用统计行数函数
  47.             # 还记得异常的用法吗?如果字典中不存,抛出 KeyError,则添加字典键
  48.             # 统计文件数
  49.             try:
  50.                 file_list[ext] += 1
  51.             except KeyError:
  52.                 file_list[ext] = 1
  53.             # 统计源代码行数
  54.             try:
  55.                 source_list[ext] += lines
  56.             except KeyError:
  57.                 source_list[ext] = lines
  58.             

  59.         # 如果路径还有文件夹,进入该文件夹继续搜索
  60.         if os.path.isdir(each_file) :
  61.             search_file(each_file) # 递归调用
  62.             os.chdir(os.pardir) # 递归调用后切记返回上一层目录(**这点很关键**)
  63.             
  64. target = ['.c', '.cpp', '.py', '.cc', '.java', '.pas', '.asm','.txt']
  65. file_list = {}     #字典file_list中 keys为扩展名,values为相应的文件数量
  66. source_list = {}   #字典source_listkeys为扩展名,values为代码行数

  67. g.msgbox("请打开您存放所有代码的文件夹......", "统计代码量")
  68. path = g.diropenbox("请选择您的代码库:",title='打开文件夹',default="C:\Program Files\Python36")

  69. search_file(path)   # 搜索文件
  70. show_result(path)   # 显示结果
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-7-31 09:52:45 | 显示全部楼层

下面代码忽略了一些编码无法正常读取的文件
  1. try:
  2.             for each_line in f:
  3.                 lines += 1
  4.         except UnicodeDecodeError:
  5.             pass # 不可避免会遇到格式不兼容的文件,这里忽略掉......
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-8-1 23:43:37 | 显示全部楼层    本楼为最佳答案   
给你整了段解决文件编码问题的代码:
1,首先安装 https://pypi.python.org/pypi/chardet(3.0以上安装方法:下载.gz文件,解压后,进入chardet目录,执行 setup.py install )
2,代码修改处:
  1. #以rb读取文件返回文件的编码(用到了chardet类)
  2.         with open(file_name, 'rb') as f:
  3.             raw = f.read()
  4.             result = chardet.detect(raw)  
  5.             encoding = result['encoding']

  6.         lines = 0   
  7.         with open(file_name,encoding=encoding) as f:
  8.             print('正在分析文件:%s ...' % file_name)     
  9.             try:
  10.                 for each_line in f:
  11.                     lines += 1
  12.             except Exception as reason:
  13.                 print(str(reason)) # 读取出错显示错误信息......
  14.         print('%s -> %s' % (file_name,lines))
  15.         return lines
复制代码


3,完整代码:
  1. import easygui as g
  2. import os
  3. import chardet

  4. # 显示结果函数:
  5. # source_list字典中keys为扩展名,values为行数;
  6. # file_list字典中keys为扩展名,values为相应类型的文件数;
  7. def show_result(start_dir):
  8.     lines = 0
  9.     total = 0
  10.     text = ""

  11.     for i in source_list:
  12.         lines = source_list[i]  # 读取不同类型代码的行数
  13.         total += lines          # 累加到total中
  14.         text += "【%s】源文件 %d 个,源代码 %d 行\n" % (i, file_list[i], lines)
  15.         # 以上(i, file_list[i], lines)是(扩展名,文件数,该类型文件代码量)
  16.         # 如(py,10,5700)即10个py文件,总共5700行代码
  17.         
  18.     title = '统计结果'
  19.     msg = '您目前共累积编写了 %d 行代码,完成进度:%.2f %%\n离 10 万行代码还差 %d 行,请继续努力!' % (total, total/1000, 100000-total)
  20.    
  21.     g.textbox(msg, title, text)

  22. # 统计行数函数:统计文件中的行数,file_name为文件名
  23. def calc_code(file_name):
  24.         #以rb读取文件返回文件的编码(用到了chardet类)
  25.         with open(file_name, 'rb') as f:
  26.             raw = f.read()
  27.             result = chardet.detect(raw)  
  28.             encoding = result['encoding']

  29.         lines = 0   
  30.         with open(file_name,encoding=encoding) as f:
  31.             print('正在分析文件:%s ...' % file_name)     
  32.             try:
  33.                 for each_line in f:
  34.                     lines += 1
  35.             except Exception as reason:
  36.                 print(str(reason)) # 读取出错显示错误信息......
  37.         print('%s -> %s' % (file_name,lines))
  38.         return lines


  39. # 根据指定路径搜索文件函数

  40. def search_file(start_dir) :
  41.     os.chdir(start_dir)   # 把指定路径改成工作路径,有了这行代码,后面文件操作会很简单
  42.    
  43.     for each_file in os.listdir(os.curdir) :
  44.         ext = os.path.splitext(each_file)[1]
  45.         if ext in target :
  46.             lines = calc_code(each_file) # 调用统计行数函数
  47.             # 还记得异常的用法吗?如果字典中不存,抛出 KeyError,则添加字典键
  48.             # 统计文件数
  49.             try:
  50.                 file_list[ext] += 1
  51.             except KeyError:
  52.                 file_list[ext] = 1
  53.             # 统计源代码行数
  54.             try:
  55.                 source_list[ext] += lines
  56.             except KeyError:
  57.                 source_list[ext] = lines
  58.             

  59.         # 如果路径还有文件夹,进入该文件夹继续搜索
  60.         if os.path.isdir(each_file) :
  61.             search_file(each_file) # 递归调用
  62.             os.chdir(os.pardir) # 递归调用后切记返回上一层目录(**这点很关键**)
  63.             
  64. target = ['.c', '.cpp', '.py', '.cc', '.java', '.pas', '.asm','.txt']
  65. file_list = {}     #字典file_list中 keys为扩展名,values为相应的文件数量
  66. source_list = {}   #字典source_listkeys为扩展名,values为代码行数

  67. g.msgbox("请打开您存放所有代码的文件夹......", "统计代码量")
  68. path = g.diropenbox("请选择您的代码库:",title='打开文件夹',default="C:\Program Files\Python36")

  69. search_file(path)   # 搜索文件
  70. show_result(path)   # 显示结果
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-1-30 16:59:39 | 显示全部楼层
根据小甲鱼老师的课后作业参考答案,我敲了代码,计算文件行数那里,我找了3种方法,方法一和方法二明显不对,行数太少。方法三行数是对的。用到一个新的模块linecache,需要先导入:
  1. import easygui as eg
  2. import os
  3. import linecache

  4. def calc_code(filename):
  5.         lines = 0
  6.         with open(filename, 'r') as f:
  7.                 print('正在计算文件%s的代码行数...'%filename)
  8.                 try:
  9.                         for each_line in f:                       #计算文件行数方法一
  10.                                 lines += 1
  11.                        
  12.                         # lines = len(f.readlines())                  #计算文件行数方法二
  13.                         # lines = len(linecache.getlines(filename))   #计算文件行数方法三
  14.                
  15.                 except UnicodeDecodeError:
  16.                         pass
  17.         return lines

  18. def search_file(path):
  19.         os.chdir(path)
  20.         for each_file in os.listdir(os.curdir):
  21.                 ext = os.path.splitext(each_file)[1]
  22.                 if ext in target:
  23.                         lines = calc_code(each_file)
  24.                         try:       
  25.                                 file_list[ext] += 1
  26.                         except KeyError:
  27.                                 file_list[ext] = 1
  28.                         try:
  29.                                 code_list[ext] += lines
  30.                         except KeyError:
  31.                                 code_list[ext] = lines
  32.                 if os.path.isdir(each_file):
  33.                         search_file(each_file)
  34.                         os.chdir(os.pardir)

  35. def show_result(path):
  36.         total = 0
  37.         lines = 0
  38.         text = ''
  39.         for i in code_list:
  40.                 lines = code_list[i]
  41.                 total += lines
  42.                 text += '【%s】源文件%d个,源代码%d行\n'%(i, file_list[i], lines)
  43.         msg = '您目前共累计编写了%d行代码,完成进度:%.2f%%\n离10万行代码还差%d行,请继续努力!'%(total, (total/100000)*100, 100000-total)
  44.         title = '统计结果'
  45.         eg.textbox(msg, title, text)

  46. target = ['.py', '.java', '.c', '.pas', '.cpp', '.asm', '.h']
  47. file_list = {}
  48. code_list = {}
  49. eg.msgbox('请打开您存放所有代码的文件夹......', '统计代码量')
  50. path = eg.diropenbox('请选择您的代码库:')
  51. search_file(path)
  52. show_result(path)


复制代码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-1-30 17:04:41 | 显示全部楼层
代码运行结果

方法三得到的总代码行数

方法三得到的总代码行数

方法一和方法二得到的总代码行数

方法一和方法二得到的总代码行数
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-24 20:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表