前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >真棒!彻底解决了一直困扰的编码问题

真棒!彻底解决了一直困扰的编码问题

作者头像
数据STUDIO
发布2021-06-24 11:23:42
1.2K0
发布2021-06-24 11:23:42
举报
文章被收录于专栏:数据STUDIO

在批量处理文件(后缀包括 ".csv"、".xlsx"、".xls"的文件)时,可能会出现同一个文件夹内同时存在不同编码的文件;亦或非"utf-8"格式的其他格式,即便相同格式也会出现有些文件能打开,而有些文件不能打开。

尤其是从SQL中导出的csv文件中,更容易出现因编码不同,使用pandas打开时报错的情况。

接下来介绍几种不同的解决方式,主要思想是将原始(编码)文件转换成目标(编码)文件utf-8,再用工具读取。

不使用任何三方包

一般转换方法

代码语言:javascript
复制
def correctSubtitleEncoding(filename, 
                            newFilename, 
                            encoding_from, 
                            encoding_to='UTF-8'):
    with open(filename, 'r', encoding=encoding_from) as fr:
        with open(newFilename, 'w', encoding=encoding_to) as fw:
            for line in fr:
                fw.write(line[:-1]+'\r\n')

暴力转换

代码语言:javascript
复制
filelocation = ""
outputfilelocation = ""

try:
    # open the CSV file
    inputfile = open(filelocation, 'rb')
    outputfile = open(outputfilelocation, 'w', encoding='utf-8')
    for line in inputfile:
        if line[-2:] == b'\r\n' or line[-2:] == b'\n\r':
            output = line[:-2].decode('utf-8', 'replace') + '\n'
        elif line[-1:] == b'\r' or line[-1:] == b'\n':
            output = line[:-1].decode('utf-8', 'replace') + '\n'
        else:
            output = line.decode('utf-8', 'replace') + '\n'
        outputfile.write(output)
    outputfile.close()
except BaseException as error:
    print("Error(18): opening CSV-file " + filelocation + " failed: " + str(error))

使用chardet模块

chardet模块有两种用法

1、检测特定页面的编码格式

代码语言:javascript
复制
with open(file, 'rb') as f:
  rawdata = f.read()
  detect(rawdata)
    
>>> {'confidence': 0.99, 'encoding': 'utf-8'}

结果分析: 其准确率99%的概率,编码格式为 'utf-8'

2、增量检测编码格式

代码语言:javascript
复制
def get_encoding_type(current_file):
    detector.reset()
    for line in file(current_file):
        detector.feed(line)
        if detector.done: break
    detector.close()
    return detector.result['encoding']

为了提高预测的准确性,基于dector.feed()来实现持续的信息输入,在信息足够充足之后结束信息输入,给出相应的预测和判断。 如果需要复用detector方法,需要进行detector.reset()进行重置,从而可以复用。

自动检测原始文件编码,再转换。

代码语言:javascript
复制
import os    
from chardet import detect

# get file encoding type
def get_encoding_type(file):
    with open(file, 'rb') as f:
        rawdata = f.read()
    return detect(rawdata)['encoding']

from_codec = get_encoding_type(srcfile)

# add try: except block for reliability
try: 
    with open(srcfile, 'r', encoding=from_codec) as f, open(trgfile, 'w', encoding='utf-8') as e:
        text = f.read() # 小文件使用read, 大文件使用chunks
        e.write(text)

    os.remove(srcfile) # 删除原始文件
    os.rename(trgfile, srcfile) # 重命名新文件 
except UnicodeDecodeError:
    print('Decode Error')
except UnicodeEncodeError:
    print('Encode Error')

使用codecs模块

codecs模块[1]

当python要做编码转换的时候,会借助于内部的编码,转换过程是这样的:

原有编码 -> 内部编码 -> 目的编码

python的内部是使用unicode来处理的,但是unicode的使用需要考虑的是它的编码格式有两种:

  • 一是UCS-2,它一共有65536个码位,
  • 另一种是UCS-4,它有2147483648g个码位。

对于这两种格式,python都是支持的,这个是在编译时通过--enable- unicode=ucs2--enable-unicode=ucs4来指定的。

代码语言:javascript
复制
import sys
print(sys.maxunicode)

如果输出的值为65535,那么就是UCS-2;如果输出是1114111就是UCS-4编码。

codecs专门用作编码转换

以下通过几个例子来初步了解下该模块的主要功能:

代码语言:javascript
复制
# 创建utf-8编码器  
look = codecs.lookup("utf-8")

name = 'DataStudio'
# 把name编码为内部的 unicode
tem_name = look.decode(name)
# tem_name[0]是数据,tem_name[1]是长度,这个时候的类型是unicode

# 把内部编码的unicode转换为utf-8编码的字符串
name =look.encode(b[0])

# 用codecs提供的open方法来指定打开的文件的语言编码,
# 它会在读取的时候自动转换为内部unicode  
file = codecs.open("dddd.txt", 'r', "big5")

CSV 转存 UTF-8 格式

代码语言:javascript
复制
import codecs

src="......\\xxxx.csv"
dst="......\\xxx_utf8.csv"

def ReadFile(filePath):
    with codecs.open(filePath, "r") as f:
        return f.read()

def WriteFile(filePath, u, encoding="utf-8"):
    # with codecs.open(filePath,"w",encoding) as f:
    with codecs.open(filePath, "wb") as f:
        f.write(u.encode(encoding, errors="ignore"))

def CSV_2_UTF8(src, dst):
    content = ReadFile(src)
    WriteFile(dst, content, encoding="utf-8")
    
CSV_2_UTF8(src, dst)

UTF-8-SIG 转存 UTF-8

代码语言:javascript
复制
import codecs

src="......\\xxxx.csv"
dst="......\\xxx_utf8.csv"

def ReadFile(filePath,encoding="utf-8-sig"):
    with codecs.open(filePath,"r",encoding) as f:
        return f.read()

def WriteFile(filePath,u,encoding="utf-8"):
    #with codecs.open(filePath,"w",encoding) as f:
    with codecs.open(filePath,"wb") as f:
        f.write(u.encode(encoding,errors="ignore"))

def UTF8_2_GBK(src,dst):
    content = ReadFile(src,encoding="utf-8-sig")
    WriteFile(dst,content,encoding="utf-8")

UTF8_2_GBK(src,dst)

综合以上方法

python中转换文件[2]

代码语言:javascript
复制
from __future__ import with_statement

import os
import sys
import codecs
from chardet.universaldetector import UniversalDetector

targetFormat = 'utf-8'
outputDir = 'converted'
detector = UniversalDetector()

def get_encoding_type(current_file):
    detector.reset()
    for line in file(current_file):
        detector.feed(line)
        if detector.done: break
    detector.close()
    return detector.result['encoding']

def convertFileBestGuess(filename):
   sourceFormats = ['ascii', 'iso-8859-1']
   for format in sourceFormats:
     try:
        with codecs.open(fileName, 'rU', format) as sourceFile:
            writeConversion(sourceFile)
            print('Done.')
            return
      except UnicodeDecodeError:
        pass


def writeConversion(file):
    with codecs.open(outputDir + '/' + fileName, 'w', targetFormat) as targetFile:
        for line in file:
            targetFile.write(line)
              
            
def convertFileWithDetection(fileName):
    print("Converting '" + fileName + "'...")
    format=get_encoding_type(fileName)
    try:
        with codecs.open(fileName, 'rU', format) as sourceFile:
            writeConversion(sourceFile)
            print('Done.')
            return
    except UnicodeDecodeError:
        pass

    print("Error: failed to convert '" + fileName + "'.")

# Off topic: get the file list and call convertFile on each file
# ...

这合并了原始的尝试多种格式,以及使用chardet.universaldetector,不断尝试直到没有异常的转码方法。

使用Notepad++

巧用notepad++[3] 批量转换 ansiutf8notepad++中使用python脚本[4]

NotePad++下载地址[5]

  • 运行Notepad ++,然后打开菜单Plugins(插件)-> Plugin Manager(插件管理)-> Show Plugin Manager
  • 安装PythonScript(Python脚本)。安装插件后,重新启动应用程序。
  • 选择菜单Plugins(插件)-> PythonScript(Python脚本)->New script(新建脚本)
  • 选择它的名称,然后加上以下代码。

convertToUTF8.py

代码语言:javascript
复制
import os
import sys
from Npp import notepad # import it first!

filePathSrc="C:\\Users\\" # Path to the folder with files to convert
for root, dirs, files in os.walk(filePathSrc):
    for fn in files: 
        if fn[-4:] == '.csv': # Specify type of the files
            notepad.open(root + "\\" + fn)      
            notepad.runMenuCommand("Encoding", "Convert to UTF-8")
            # notepad.save()
            # if you try to save/replace the file, 
            # an annoying confirmation window would popup.
            notepad.saveAs("{}{}".format(fn[:-4], '_utf8.csv')) 
            notepad.close()

动画演示

然后运行

使用记事本转换格式

记事本是个强大的文本编辑软件,在少量文件或未知原始文件编码的情况下,使用记事本转换编码很是方便。

  • 选中需要转换的原始文件,右击打开方式为记事本
  • 文件 -> 另存为 -> 选择编码方式"utf-8" -> 保存
  • 再次打开检查文件编码

各中文编码

各语言标准编码[6]

以下仅展示来中文编码,其他标准编码请见参考资料。

Codec编码器

Aliases别名

语言能力

ascii

646, us-ascii

英语

big5

big5-tw, csbig5

繁体中文

big5hkscs

big5-hkscs, hkscs

繁体中文

cp037

IBM037, IBM039

英语

cp437

437, IBM437

英语

cp950

950, ms950

繁体中文

gb2312

chinese, csiso58gb231280, euc-cn, euccn, eucgb2312-cn, gb2312-1980, gb2312-80, iso-ir-58

简体中文

gbk

936, cp936, ms936

统一中文

gb18030

gb18030-2000

统一中文

hz

hzgb, hz-gb, hz-gb-2312

简体中文

iso2022_jp_2

iso2022jp-2, iso-2022-jp-2

日文,韩文,简体中文,西欧,希腊文

latin_1

iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1

西欧

iso8859_2

iso-8859-2, latin2, L2

中欧和东欧

iso8859_3

iso-8859-3, latin3, L3

世界语,马耳他语

iso8859_4

iso-8859-4, latin4, L4

波罗的海语言

utf_32

U32, utf32

所有语言

utf_32_be

UTF-32BE

所有语言

utf_32_le

UTF-32LE

所有语言

utf_16

U16, utf16

所有语言

utf_16_be

UTF-16BE

所有语言

utf_16_le

UTF-16LE

所有语言

utf_7

U7, unicode-1-1-utf-7

所有语言

utf_8

U8, UTF, utf8, cp65001

所有语言

utf_8_sig

所有语言

参考资料 [1]codecs模块: https://docs.python.org/2/library/codecs.html [2] python中转换文件: https://stackoverflow.com/questions/191359/how-to-convert-a-file-to-utf-8-in-python [3]巧用notepad++: https://stackoverflow.com/questions/7256049/how-do-i-convert-an-ansi-encoded-file-to-utf-8-with-notepad [4] notepad++中使用python脚本: https://blog.csdn.net/tomato__/article/details/46915869 [5] NotePad++下载地址: https://notepad-plus-plus.org/downloads/ [6]各语言标准编码: https://docs.python.org/3/library/codecs.html#standard-encodings

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据STUDIO 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 不使用任何三方包
    • 一般转换方法
      • 暴力转换
        • chardet模块有两种用法
    • 使用chardet模块
      • 1、检测特定页面的编码格式
        • 2、增量检测编码格式
          • 自动检测原始文件编码,再转换。
          • 使用codecs模块
            • CSV 转存 UTF-8 格式
              • UTF-8-SIG 转存 UTF-8
              • 综合以上方法
              • 使用Notepad++
              • 使用记事本转换格式
              • 各中文编码
                • 参考资料 [1]codecs模块: https://docs.python.org/2/library/codecs.html [2] python中转换文件: https://stackoverflow.com/questions/191359/how-to-convert-a-file-to-utf-8-in-python [3]巧用notepad++: https://stackoverflow.com/questions/7256049/how-do-i-convert-an-ansi-encoded-file-to-utf-8-with-notepad [4] notepad++中使用python脚本: https://blog.csdn.net/tomato__/article/details/46915869 [5] NotePad++下载地址: https://notepad-plus-plus.org/downloads/ [6]各语言标准编码: https://docs.python.org/3/library/codecs.html#standard-encodings
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档