不弃_ 发表于 2022-2-14 11:46:51

编译器无法解码

代码报错:
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)))


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 = 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:
            if os.path.splitext(each_file) == '.txt': # 根据后缀判断是否文本文件
                each_file = os.path.join(i, 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)

isdkz 发表于 2022-2-14 11:50:59

编码问题,需要把f = open(file_name,encoding='utf-8')这句的 'utf-8'改成 'gbk

不弃_ 发表于 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

isdkz 发表于 2022-2-14 11:57:09

本帖最后由 isdkz 于 2022-2-14 11:58 编辑

不弃_ 发表于 2022-2-14 11:53
还是报错
请将该脚本放于待查找的文件夹内,请输入关键字:'3'
请问是否需要打印关键字【'3'】在文件中 ...

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

这个可以用python内置模块chardet,你可以先按我说的研究一下,我帮你调试好了再放代码上来

Twilight6 发表于 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) 设置好文件编码,打开文件

isdkz 发表于 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)))


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 = 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:
            if os.path.splitext(each_file) == '.txt': # 根据后缀判断是否文本文件
                each_file = os.path.join(i, 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: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)

isdkz 发表于 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'
>>>

不弃_ 发表于 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()

isdkz 发表于 2022-2-14 12:27:40

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


找不到就安装一下吧,我看网上说这个模块是内置的

isdkz 发表于 2022-2-14 12:30:52

还有个问题就是你判断输入的选项的时候大小写混用有很多种情况,你不能把每一种都枚举出来,你可以先处理一下输入

if detail in ['YES', 'Yes', 'yes']:
    print_pos(key_dict)
改成
if detail.lower() == 'yes:
    print_pos(key_dict)

不弃_ 发表于 2022-2-14 12:31:21

isdkz 发表于 2022-2-14 12:18
open的默认编码是根据当前的语言环境,你可以使用locale模块查看

那就是说所有文件有两个或两个以上的编码,open()就打不开报错。只要统一编码就不会报错。
是这样的吗?

不弃_ 发表于 2022-2-14 12:33:14

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

不错

isdkz 发表于 2022-2-14 12:34:11

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

对的,默认它不会帮你自动检测编码,而是根据你当前语言环境给你指定的
页: [1]
查看完整版本: 编译器无法解码