鱼C论坛

 找回密码
 立即注册
查看: 1669|回复: 13

[已解决]编译器无法解码

[复制链接]
发表于 2022-2-14 11:46:51 | 显示全部楼层 |阅读模式

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

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

x
代码报错:
utf-8”编解码器无法解码位置3中的字节0xd0:无效的继续字节


查找文件中关键字的具体位置代码如下:
import os

def print_pos(key_dict):
    keys = key_dict.keys()
    keys = sorted(keys) # 由于字典是无序的,我们这里对行数进行排序
    for each_key in keys:
        print('关键字出现在第 %s 行,第 %s 个位置。' % (each_key, str(key_dict[each_key])))


def pos_in_line(line, key):
    pos = []
    begin = line.find(key)
    while begin != -1:
        pos.append(begin + 1) # 用户的角度是从1开始数
        begin = line.find(key, begin+1) # 从下一个位置继续查找

    return pos


def search_in_file(file_name, key):
    f = open(file_name,encoding='utf-8')
    count = 0 # 记录行数
    key_dict = dict() # 字典,用户存放key所在具体行数对应具体位置
   
    for each_line in f:
        count += 1
        if key in each_line:
            pos = pos_in_line(each_line, key) # key在每行对应的位置
            key_dict[count] = pos
   
    f.close()
    return key_dict


def search_files(key, detail):   
    all_files = os.walk(os.getcwd())
    txt_files = []

    for i in all_files:
        for each_file in i[2]:
            if os.path.splitext(each_file)[1] == '.txt': # 根据后缀判断是否文本文件
                each_file = os.path.join(i[0], each_file)
                txt_files.append(each_file)

    for each_txt_file in txt_files:
        key_dict = search_in_file(each_txt_file, key)
        if key_dict:
            print('================================================================')
            print('在文件【%s】中找到关键字【%s】' % (each_txt_file, key))
            if detail in ['YES', 'Yes', 'yes']:
                print_pos(key_dict)


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

最佳答案
2022-2-14 12:34:11
不弃_ 发表于 2022-2-14 12:31
那就是说所有文件有两个或两个以上的编码,open()就打不开报错。只要统一编码就不会报错。
是这样的吗?

对的,默认它不会帮你自动检测编码,而是根据你当前语言环境给你指定的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-2-14 11:50:59 | 显示全部楼层
编码问题,需要把f = open(file_name,encoding='utf-8')这句的 'utf-8'改成 'gbk
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2022-2-14 11:53:08 | 显示全部楼层
isdkz 发表于 2022-2-14 11:50
编码问题,需要把f = open(file_name,encoding='utf-8')这句的 'utf-8'改成 'gbk

还是报错
请将该脚本放于待查找的文件夹内,请输入关键字:'3'
请问是否需要打印关键字【'3'】在文件中的具体位置(YES/NO):yes
Traceback (most recent call last):
  File "E:/编码程序/python/n2n14.py", line 56, in <module>
    search_files(key, detail)
  File "E:/编码程序/python/n2n14.py", line 46, in search_files
    key_dict = search_in_file(each_txt_file, key)
  File "E:/编码程序/python/n2n14.py", line 25, in search_in_file
    for each_line in f:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xab in position 74: illegal multibyte sequence
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-2-14 11:57:09 | 显示全部楼层
本帖最后由 isdkz 于 2022-2-14 11:58 编辑
不弃_ 发表于 2022-2-14 11:53
还是报错
请将该脚本放于待查找的文件夹内,请输入关键字:'3'
请问是否需要打印关键字【'3'】在文件中 ...


因为你的文件不一定统一编码,你可以以二进制打开,一次读取所有的内容,检测一下编码再解码

这个可以用python内置模块chardet,你可以先按我说的研究一下,我帮你调试好了再放代码上来
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-2-14 11:58:13 | 显示全部楼层

像这种需要遍历整个文件夹下 txt 文本的,容易出现编码不一致问题

你可能前一个文件是 utf-8 的编码,而后一个就是 Gbk 编码,又或者是其他

所以若你单纯想测试代码,可以将代码中的 txt 文件全部重新另存为 设置编码统一的编码集

若你想通用,就需要用到 chardet 模块,进行读取文件对象的编码,通过 open 的 'rb' 模式二进制读取文件对象 f

然后调用,ed = chardet.detect(f.read())['encoding'] 就可以获取此时文件的编码

再重新通过 open(file_name,encoding = ed) 设置好文件编码,打开文件

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

使用道具 举报

发表于 2022-2-14 12:09:37 | 显示全部楼层
本帖最后由 isdkz 于 2022-2-14 12:24 编辑

你先看一下,我还没有测试,有问题再讨论
import os
import chardet                   #   加上这句

def print_pos(key_dict):
    keys = key_dict.keys()
    keys = sorted(keys) # 由于字典是无序的,我们这里对行数进行排序
    for each_key in keys:
        print('关键字出现在第 %s 行,第 %s 个位置。' % (each_key, str(key_dict[each_key])))


def pos_in_line(line, key):
    pos = []
    begin = line.find(key)
    while begin != -1:
        pos.append(begin + 1) # 用户的角度是从1开始数
        begin = line.find(key, begin+1) # 从下一个位置继续查找

    return pos


def search_in_file(file_name, key):
    with open(file_name, 'rb') as f:                  #    改这里
        raw = f.read()                                 #    加上这句
    if not raw:                                        #     加上这句
        return                                     # 加上这句
    text = raw.decode(chardet.detect(raw)['encoding'])       #    加上这句
    lines = text.splitlines()

    count = 0 # 记录行数
    key_dict = dict() # 字典,用户存放key所在具体行数对应具体位置
   
    for each_line in lines:                       #   f改成lines
        count += 1
        if key in each_line:
            pos = pos_in_line(each_line, key) # key在每行对应的位置
            key_dict[count] = pos
   
    # f.close()            删掉这句
    return key_dict


def search_files(key, detail):   
    all_files = os.walk(os.getcwd())
    txt_files = []

    for i in all_files:
        for each_file in i[2]:
            if os.path.splitext(each_file)[1] == '.txt': # 根据后缀判断是否文本文件
                each_file = os.path.join(i[0], each_file)
                txt_files.append(each_file)

    for each_txt_file in txt_files:
        key_dict = search_in_file(each_txt_file, key)
        if key_dict:
            print('================================================================')
            print('在文件【%s】中找到关键字【%s】' % (each_txt_file, key))
            if detail in ['YES', 'Yes', 'yes']:
                print_pos(key_dict)


key = input('请将该脚本放于待查找的文件夹内,请输入关键字:')
detail = input('请问是否需要打印关键字【%s】在文件中的具体位置(YES/NO):' % key)
search_files(key, detail)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-2-14 12:11:45 | 显示全部楼层
isdkz 发表于 2022-2-14 12:09
你先看一下,我还没有测试,有问题再讨论

open()的默认编码是gbk吗?open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-2-14 12:18:47 | 显示全部楼层
不弃_ 发表于 2022-2-14 12:11
open()的默认编码是gbk吗?open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=No ...

open的默认编码是根据当前的语言环境,你可以使用locale模块查看
>>> import locale
>>> locale.getpreferredencoding()
'cp936'
>>>
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-2-14 12:25:07 | 显示全部楼层
isdkz 发表于 2022-2-14 12:09
你先看一下,我还没有测试,有问题再讨论

报错
Traceback (most recent call last):
  File "E:/编码程序/python/n2n14.py", line 2, in <module>
    import chardet                   #   加上这句
ModuleNotFoundError: No module named 'chardet'
locale.getpreferredencoding()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-2-14 12:27:40 | 显示全部楼层
不弃_ 发表于 2022-2-14 12:25
报错
Traceback (most recent call last):
  File "E:/编码程序/python/n2n14.py", line 2, in

找不到就安装一下吧,我看网上说这个模块是内置的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-2-14 12:30:52 | 显示全部楼层
还有个问题就是你判断输入的选项的时候大小写混用有很多种情况,你不能把每一种都枚举出来,你可以先处理一下输入
if detail in ['YES', 'Yes', 'yes']:
    print_pos(key_dict)
改成
if detail.lower() == 'yes:
    print_pos(key_dict)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-2-14 12:31:21 | 显示全部楼层
isdkz 发表于 2022-2-14 12:18
open的默认编码是根据当前的语言环境,你可以使用locale模块查看

那就是说所有文件有两个或两个以上的编码,open()就打不开报错。只要统一编码就不会报错。
是这样的吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-2-14 12:33:14 | 显示全部楼层
isdkz 发表于 2022-2-14 12:30
还有个问题就是你判断输入的选项的时候大小写混用有很多种情况,你不能把每一种都枚举出来,你可以先处理一 ...

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

使用道具 举报

发表于 2022-2-14 12:34:11 | 显示全部楼层    本楼为最佳答案   
不弃_ 发表于 2022-2-14 12:31
那就是说所有文件有两个或两个以上的编码,open()就打不开报错。只要统一编码就不会报错。
是这样的吗?

对的,默认它不会帮你自动检测编码,而是根据你当前语言环境给你指定的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-12 06:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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