鱼C论坛

 找回密码
 立即注册
查看: 807|回复: 9

[已解决]第30讲 第4题 查找关键字的具体位置 为啥我的程序跑不对啊

[复制链接]
发表于 2020-4-22 17:36:32 | 显示全部楼层 |阅读模式

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

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

x

代码思路我都写在注释里了,为什么跑不出来啊,请各位帮忙看看吧!谢谢大家

主要思路就是:一个文件有关键字,这个文件创一个列表each_txt,列表里放字典line_site,字典的键是行数line_num,值是列数site_num(字符位置)且值site_num也是一个列表(因为有多个位置)
import os

paths = []       # 存放有关键字的文件的路径
each_txt = []    # 存放每个文件中每个关键字{行:列}字典的列表

def search_keyword(keyword) :   
    all_files = os.listdir(os.curdir)
    
    for each_file in all_files:
        ext = os.path.splitext(each_file)[1]
        
        if os.path.isdir(each_file) :
            os.chdir(each_file)
            search_keyword(keyword)   
            os.chdir(os.pardir)  
            
        if ext == '.txt':
            path = os.getcwd() + os.sep + each_file   # path保存文本文件路径
            f = open(each_file)
            line_site = dict()   # 存放每个关键字{行:列}的字典,每个新文件都要置空
            line_num = 0  
            
            for each_line in f:
                site_num = []    # 存放【列】的列表,每一行查找时都要置空
                line_num += 1    # 每行的行数每次 +1
                
                while 1:
                    i = 0
                    site = each_line.find(keyword, i)   # 查找关键字,如果有返回关键字的第一个索引号(即列),没有返回-1
                    if site != -1:             # 查到关键字
                        site_num.append(site)  # 将关键字的第一个索引号即列值加入列表中
                        i = site + 1           # 从site后一个位置查找这一行还有没有关键字(11在1111中的数目
                    else:                      # 如果没有找到关键字
                        break                  # 说明each_line这一行检索完毕或根本没有关键字,退出while循环查找下一行
                        
                if site_num == []:                  # 如果【列】的列表是空的,说明这一行没有关键字
                    continue                        # 继续查找下一行
                else:                               # 如果【列】的列表不是空的,说明这一行有关键字
                    line_site[line_num] = site_num  # 在字典中添加{行数(数字):列数【列表】}
                    each_txt.append(line_site)      # 在这个文件的列表中添加字典
                    
            if line_site == {}:      # 如果字典是空的,说明没有{行:列}添加,即此文件中没有关键字
                continue             # 退出查找每行的for循环,查找下一文件
            else:                    # 如果字典不是空的,说明有{行:列}添加,即此文件中有关键字
                paths.append(path)   # 添加此文件的路径
                
            f.close()
            
keyword = input('请将该脚本放于待查找的文件夹内,请输入关键字:')
search_keyword(keyword)      
decide = input('请问是否需要打印关键字【%s】在文件中大的具体位置(YES/NO):' % keyword)

if decide in ['YES', 'yes', 'Yes']:
    
    if paths == []:    # 为空说明没有存在关键字的文件
        print('===================================================')
        print('当前文件夹内所有文本文件均不含有此关键字!')
    else:
        print('===================================================')
        
        for each_path in paths:    # paths有一个元素就说明有一个文件有关键字
            print('在文件【%s】中找到关键字【%s】' % (each_path, keyword))            
            
            for each_line_site in each_txt:    # each_txt是一个列表(每个文件一个列表),每个元素each_line_site都为字典
                
                for each_item in each_line_site.items():    # each_item是字典的每一项,是一个元组(键(行),值(列))
                    print('关键字出现在第 %d 行,第' % each_item(0), each_item(1), '个位置。')  # 值(列)是一个列表
最佳答案
2020-4-24 01:56:01
本帖最后由 txxcat 于 2020-4-24 01:58 编辑
yangxuebabe 发表于 2020-4-23 22:00
您好 我按照您说的修改了
但是结果还是有点问题


你的代码还有几处错误,看注释:
import os

paths = []       # 存放有关键字的文件的路径
each_txt = []    # 存放每个文件中每个关键字{行:列}字典的列表

def copen(filename):
    try:
        f = open(filename,encoding='GBK') 
        try:
            f.read()
            f.seek(0)
        except UnicodeDecodeError:
            f = open(filename,encoding='utf-8',errors='ignore')
    except (OSError,AttributeError) as reason: 
        print(str(reason))
        return None
    return f

def search_keyword(keyword) :   
    all_files = os.listdir(os.curdir)
    
    for each_file in all_files:
        ext = os.path.splitext(each_file)[1]
        
        if os.path.isdir(each_file) :
            os.chdir(each_file)
            search_keyword(keyword)   
            os.chdir(os.pardir)  
            
        if ext == '.txt':
            path = os.getcwd() + os.sep + each_file 
            f = copen(each_file)      #用函数copen打开防止编码错误
            line_site = dict() 
            line_num = 0  
            
            for each_line in f:
                site_num = []
                line_num += 1
                
                i = 0
                while 1:
                    site = each_line.find(keyword, i) 
                    if site != -1: 
                        site_num.append(site+1)            #python索引从0开始,人类习惯1开始
                        i = site + 1
                    else: 
                        break 
                        
                if site_num == []: 
                    continue
                else: 
                    line_site[line_num] = site_num
#                    each_txt.append(line_site)          #在这里append,每找到一行就append一次,重复数据导致错误
                    
            if line_site == {}:
                continue
            else:
                paths.append(path)
                each_txt.append(line_site)               #在这里append就不会有重复数据
            f.close()

keyword = input('请将该脚本放于待查找的文件夹内,请输入关键字:')
search_keyword(keyword)      
decide = input('请问是否需要打印关键字【%s】在文件中大的具体位置(YES/NO):' % keyword)

if decide.strip().lower()=='yes':              #这样可以对付任意大小写组合,还有空格
    
    if paths == []:
        print('===================================================')
        print('当前文件夹内所有文本文件均不含有此关键字!')
    else:
        print('===================================================')
        for i in range(len(paths)):                                       #原有的代码是有多少符合条件的文件,就把所有的答案重复打印多少次
            print('在文件【%s】中找到关键字【%s】' % (paths[i], keyword))   #只打印和文件对应的字典
            for j,k in each_txt[i].items():
                print('关键字出现在第 %d 行,第%s个位置。' % (j, k)) 
                
#         for each_path in paths:    # paths有一个元素就说明有一个文件有关键字
#             print('在文件【%s】中找到关键字【%s】' % (each_path, keyword))            
#             
#             for each_line_site in each_txt:    # each_txt是一个列表(每个文件一个列表),每个元素each_line_site都为字典
#                 
#                 for each_item in each_line_site.items():    # each_item是字典的每一项,是一个元组(键(行),值(列))
#                     print('关键字出现在第 %d 行,第' % each_item[0], each_item[1], '个位置。')  # 值(列)是一个列表
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-4-22 18:52:38 | 显示全部楼层
这是个死循环:
                while 1:
                    i = 0
                    site = each_line.find(keyword, i)   # 查找关键字,如果有返回关键字的第一个索引号(即列),没有返回-1
                    if site != -1:             # 查到关键字
                        site_num.append(site)  # 将关键字的第一个索引号即列值加入列表中
                        i = site + 1           # 从site后一个位置查找这一行还有没有关键字(11在1111中的数目
                    else:                      # 如果没有找到关键字
                        break                  # 说明each_line这一行检索完毕或根本没有关键字,退出while循环查找下一行
i每次循环都初始化为0,所以只要包含关键字,就成了死循环,把i=0放在外面就可以了:
                i = 0
                while 1:
                     site = each_line.find(keyword, i)   # 查找关键字,如果有返回关键字的第一个索引号(即列),没有返回-1
                    if site != -1:             # 查到关键字
                        site_num.append(site)  # 将关键字的第一个索引号即列值加入列表中
                        i = site + 1           # 从site后一个位置查找这一行还有没有关键字(11在1111中的数目
                    else:                      # 如果没有找到关键字
                        break                  # 说明each_line这一行检索完毕或根本没有关键字,退出while循环查找下一行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-22 18:59:06 | 显示全部楼层
顺便说一下,测试的时候碰到编码错,批量处理文本文件的时候难免碰到编码不同的文件,可以参考这个帖子改一下代码:避免打开文本文件出现编码错误的一个小技巧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-23 22:00:29 | 显示全部楼层
txxcat 发表于 2020-4-22 18:52
这是个死循环:

i每次循环都初始化为0,所以只要包含关键字,就成了死循环,把i=0放在外面就可以了:

您好 我按照您说的修改了
但是结果还是有点问题

运行结果是:

请将该脚本放于待查找的文件夹内,请输入关键字:of
请问是否需要打印关键字【of】在文件中大的具体位置(YES/NO):yes
===================================================
在文件【F:\Python\JupyterProject\猪猪大数据\city.txt】中找到关键字【of】
关键字出现在第 3 行,第 [54, 93] 个位置。
关键字出现在第 7 行,第 [27, 106, 311, 401] 个位置。
关键字出现在第 3 行,第 [54, 93] 个位置。
关键字出现在第 7 行,第 [27, 106, 311, 401] 个位置。
关键字出现在第 17 行,第 [0] 个位置。
===================================================
在文件【F:\Python\JupyterProject\面朝大海,春暖花开.txt】中找到关键字【of】
关键字出现在第 3 行,第 [54, 93] 个位置。
关键字出现在第 7 行,第 [27, 106, 311, 401] 个位置。
关键字出现在第 3 行,第 [54, 93] 个位置。
关键字出现在第 7 行,第 [27, 106, 311, 401] 个位置。
关键字出现在第 17 行,第 [0] 个位置。

第3行和第7行是第一个文件的,打印了两次
第17行是第二个文件的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-24 01:56:01 | 显示全部楼层    本楼为最佳答案   
本帖最后由 txxcat 于 2020-4-24 01:58 编辑
yangxuebabe 发表于 2020-4-23 22:00
您好 我按照您说的修改了
但是结果还是有点问题


你的代码还有几处错误,看注释:
import os

paths = []       # 存放有关键字的文件的路径
each_txt = []    # 存放每个文件中每个关键字{行:列}字典的列表

def copen(filename):
    try:
        f = open(filename,encoding='GBK') 
        try:
            f.read()
            f.seek(0)
        except UnicodeDecodeError:
            f = open(filename,encoding='utf-8',errors='ignore')
    except (OSError,AttributeError) as reason: 
        print(str(reason))
        return None
    return f

def search_keyword(keyword) :   
    all_files = os.listdir(os.curdir)
    
    for each_file in all_files:
        ext = os.path.splitext(each_file)[1]
        
        if os.path.isdir(each_file) :
            os.chdir(each_file)
            search_keyword(keyword)   
            os.chdir(os.pardir)  
            
        if ext == '.txt':
            path = os.getcwd() + os.sep + each_file 
            f = copen(each_file)      #用函数copen打开防止编码错误
            line_site = dict() 
            line_num = 0  
            
            for each_line in f:
                site_num = []
                line_num += 1
                
                i = 0
                while 1:
                    site = each_line.find(keyword, i) 
                    if site != -1: 
                        site_num.append(site+1)            #python索引从0开始,人类习惯1开始
                        i = site + 1
                    else: 
                        break 
                        
                if site_num == []: 
                    continue
                else: 
                    line_site[line_num] = site_num
#                    each_txt.append(line_site)          #在这里append,每找到一行就append一次,重复数据导致错误
                    
            if line_site == {}:
                continue
            else:
                paths.append(path)
                each_txt.append(line_site)               #在这里append就不会有重复数据
            f.close()

keyword = input('请将该脚本放于待查找的文件夹内,请输入关键字:')
search_keyword(keyword)      
decide = input('请问是否需要打印关键字【%s】在文件中大的具体位置(YES/NO):' % keyword)

if decide.strip().lower()=='yes':              #这样可以对付任意大小写组合,还有空格
    
    if paths == []:
        print('===================================================')
        print('当前文件夹内所有文本文件均不含有此关键字!')
    else:
        print('===================================================')
        for i in range(len(paths)):                                       #原有的代码是有多少符合条件的文件,就把所有的答案重复打印多少次
            print('在文件【%s】中找到关键字【%s】' % (paths[i], keyword))   #只打印和文件对应的字典
            for j,k in each_txt[i].items():
                print('关键字出现在第 %d 行,第%s个位置。' % (j, k)) 
                
#         for each_path in paths:    # paths有一个元素就说明有一个文件有关键字
#             print('在文件【%s】中找到关键字【%s】' % (each_path, keyword))            
#             
#             for each_line_site in each_txt:    # each_txt是一个列表(每个文件一个列表),每个元素each_line_site都为字典
#                 
#                 for each_item in each_line_site.items():    # each_item是字典的每一项,是一个元组(键(行),值(列))
#                     print('关键字出现在第 %d 行,第' % each_item[0], each_item[1], '个位置。')  # 值(列)是一个列表
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-24 09:41:45 | 显示全部楼层
txxcat 发表于 2020-4-24 01:56
你的代码还有几处错误,看注释:

天哪太感谢了!!好细心!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-24 11:51:48 | 显示全部楼层
txxcat 发表于 2020-4-24 01:56
你的代码还有几处错误,看注释:

大神 还有一个问题,就是,如果按照我原来的代码,append会导致数据重复,我的想法重复的结果应该是:

比如在第一行的第1个字符找到关键字
那么append一个字典  [{1:1}]

然后在第二行的第2个字符找到关键字
此时字典更新为{1:1, 2:2},再次append这个字典,那此时的列表each_txt应为 [{1:1}, {1:1, 2:2}]

可是为什么程序显示的是  [{1:1, 2:2}, {1:1, 2:2}]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-24 13:49:00 | 显示全部楼层
txxcat 发表于 2020-4-24 01:56
你的代码还有几处错误,看注释:

还有一个问题。。我看了标准答案,用了sort()对字典进行排序,但是为什么我的程序没有进行排序也是自动按顺序打印的?我试了好几个关键字好多次都是按照行数顺序打印的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-24 19:09:24 | 显示全部楼层
yangxuebabe 发表于 2020-4-24 11:51
大神 还有一个问题,就是,如果按照我原来的代码,append会导致数据重复,我的想法重复的结果应该是:

...

因为append的是字典变量名而不是字典的值,做个实验:
>>> a={}
>>> a['1']=1
>>> b=[]
>>> b.append(a)
>>> b
[{'1': 1}]
>>> a['2']=2
>>> a
{'1': 1, '2': 2}
>>> b.append(a)
>>> b
[{'1': 1, '2': 2}, {'1': 1, '2': 2}]
能看明白吧?不是字典如此,列表加入列表也是如此。
为什么用sorted,个人感觉没必要,因为正常情况下字典就是按行号顺序生成的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-24 19:39:35 | 显示全部楼层
txxcat 发表于 2020-4-24 19:09
因为append的是字典变量名而不是字典的值,做个实验:

能看明白吧?不是字典如此,列表加入列表也是如 ...

不好意思还是没太明白,为啥字典a 变了之后再append,已经加进去的那个a也跟着变了,第一个a加进去了就是加进去了,加的就是当时的a,a改变是之后的事情啊,程序不是顺着读的吗?难道后面a的更改能影响第一个append的a?

关于sorted,我想是因为字典无序,每次加入元素是不是可能会打乱顺序?这样打印出来就不是按照行号的了。或者打印的时候可能会无序?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-26 20:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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