最近完成了一个项目,最后要使用pipreqs生成requirements.txt文件。然而在使用pip install pipreqs安装pipreqs库,再用pipreqs 项目根目录 --encoding=utf-8生成requirements.txt文件时,我遇到了如下报错。
(venv) D:\pycharmfiles\MDC>pipreqs D:\pycharmfiles\MDC --encoding=utf-8
ERROR: Failed on file: D:\pycharmfiles\MDC\TTS\tts\utils\text\korean\korean.py
Traceback (most recent call last):
File "D:\ProgramData\Anaconda3\lib\runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
tree = ast.parse(contents)
File "D:\ProgramData\Anaconda3\lib\ast.py", line 50, in parse
return compile(source, filename, mode, flags,
File "" , line 1
# coding: utf-8
^
SyntaxError: invalid non-printable character U+FEFF
参考文章2给出了一种解决方案。步骤如下:
方法一看着很简单,但是对我没用,因为我的文件右下角的编码是灰色的,不能修改。(整无语了)
后来我尝试在命令中把指定的编码方式从utf-8修改为utf-8-sig,成功生成requirements.txt文件。
报错原命令:
pipreqs 项目根目录 --encoding=utf-8
修改后命令:
pipreqs 项目根目录 --encoding=utf-8-sig
可以发现,报错的原因是出现了无效字符U+FEFF(即BOM),而无论是方法一还是方法二都在试图去除BOM的影响。查阅资料时我还发现了其他殊途同归的解决方法,但因为比较复杂,就没有整理在这里。那么这个东西是什么呢?
字节顺序标记(英语:byte-order mark,BOM)是位于码点U+FEFF的统一码字符的名称。当以UTF-16或UTF-32来将UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其字节序。它常被用来当做标示文件是以UTF-8、UTF-16或UTF-32编码的记号。
"ZERO WIDTH NO-BREAK SPACE"字符的UCS编码为FEFF(假设为大端),对应的UTF-8编码为 EF BB BF,即以EF BB BF开头的字节流可表明这是段UTF-8编码的字节流。但如果文件本身就是UTF-8编码的,EF BB BF这三个字节就毫无用处了。所以,可以说BOM的存在对于UTF-8本身没有任何作用。
utf-8是以字节为编码单元,它的字节顺序在所有系统中都是一样的,没有字节序问题,因此它不需要BOM,所以当用"utf-8"编码方式读取带有BOM的文件时,它会把BOM当做是文件内容来处理,也就会发生类似上边的错误。
uft-8-sig中“sig”全拼为 signature,也就是"带有签名的utf-8”,因此"utf-8-sig"读取带有BOM的utf-8文件时,会把BOM单独处理,与文本内容隔离开,也是我们期望的结果。