如题,很简单,就是先用chardet 库识别文件编码,解码之后再输出成目标编码。算是个偶尔能用上的小工具,要用的时候万一没有就很难受的那种,比如,网上下载了别人的项目文件,一打开全是乱码
加了比较详细的注释~~ 看懂的要求应该不高,平时用过Python,知道几个常用库就行。
from pathlib import Path import chardet import re def text_file_encoding_convert(f: Path, target_encoding: str, *, dry_run=False) -> (bool, str, float): ''' 转换单个文件到目标编码 @param f 文件路径 @param target_encoding 目标编码,比如urf-8 @param dry_run 为True 时不实际修改源文件 @return 返回三个值分别为(是否成功,估计的源文件编码,估计的把握) ''' target_encoding = target_encoding.lower() # python 的标准编码名称都是小写 raw = f.read_bytes() result = chardet.detect(raw) encoding = result["encoding"].lower() # chardet 估计出来的编码名称 confidence = result["confidence"] # 估计的把握 flag = True # 下面的单次for 循环用来避免重复写return 语句,break 后统一跳到最后return for _d( ̄_ ̄)b_ in (1,): if encoding == target_encoding or encoding == "ascii" and target_encoding == "utf-8": # 目标编码和源编码相同时不用做处理。utf-8 编码和ASCII 兼容,原编码为ASCII 时转换到utf-8 不会有变化,所以也跳过 print(f"-> [NO CONVERSION NEEDED] {f.name}: {encoding} ==> [ {target_encoding} ]") break try: text = raw.decode(encoding) except: print(f"!> Encoding err: {f.name}, detected: {encoding}, {confidence}.") flag = False break if dry_run: print(f"-> [ NO WET ] {f.name}: {encoding} ==> [ {target_encoding} ]") else: # 必须先用目标编码转换成字节数组,然后按字节写入源文件 # 如果按文本方式写入,就会遇到喜闻乐见的CR LF 换行问题, # 源文件中的CR LF 换行会被自动变成CR CR LF,也就是多了一堆空行。 out = text.encode(target_encoding) f.write_bytes(out) print(f"-> {f.name}: {encoding} ==> [ {target_encoding} ]") return (flag, encoding, confidence) def text_file_encoding_batch_convert( folder: Path, target_encoding: str, *, dry_run=True, recursive=False, pattern=".*(c|h|txt|cxx|cpp|hpp|hxx|csv|asm)$", skip_when_error=True, ): ''' 批量转换一个目录下文本文件的编码 @param folder 目标目录 @param target_encoding 目标编码 @param dry_run 不实际修改源文件,避免手滑写错 @param recursive 包括所有子文件夹下的文件 @param pattern 基于文件名筛选文本文件的正则表达式,默认根据后缀筛选几种文本类型 @param skip_when_error 默认True,单个文件转换出错时提示并跳过,否则终止 ''' if recursive: flist = folder.rglob("*") else: flist = folder.glob("*") p = re.compile(pattern) # 把正则编译了,之后应该能快一点 for f in flist: if not (f.is_file() and p.match(f.name)): continue ok, encoding, confidence = text_file_encoding_convert(f, target_encoding, dry_run=dry_run) if not ok: if skip_when_error: print("!> SKIP.") else: print("!> ABORT.") return
既然是批量转换文件,只调用第二个函数就好了,如下:
folder = Path(r"D:\Downloads\Some shit\\") text_file_encoding_batch_convert(folder, "utf-8", recursive=True)
目标目录为D:\Downloads\Some shit\\,放进一个Path 对象里,作为第一个参数传进去。第二个参数是目标编码,第三个参数必须写明参数名称recursive,用来指定要不要遍历子文件夹,默认是False,为了避免意外情况。直接这么运行的话,输出的信息应该类似这样:
-> [NO WET] main.c : gb2312 ⇒ utf-8
[NO WET] 意思就是DRY [doge],也就是没有实际修改源文件,只是让你大致看看输出信息对不对劲,实际运行的话再加一个参数:
text_file_encoding_batch_convert(folder, "utf-8", recursive=True, dry_run=False)
顺便一说,输出信息都是英文的,因为大伙应该都遇到过控制台输出中文乱码的问题,反正也没几个单词。剩下两个参数,skip_when_error 放着别管就行,没什么用;pattern 是匹配文件名的正则表达式,只有匹配的文件会被处理,可以自己设置;默认的正则只匹配了几种容易遇到乱码问题的文本文件,匹配的太多了也可能错杀,需要的话往括号里加就行。
The above is the detailed content of How to use Python to automatically detect and batch convert text file encodings?. For more information, please follow other related articles on the PHP Chinese website!