記事ディレクトリ
序文
今日は非常に奇妙なことを共有したいと思います。コードを書いているときに目に見えない文字に遭遇しました。!!
1. 起因
pipreqs
今日、プロジェクトをエクスポートするために依存していたライブラリを 使用しているときに、突然エラーが発生しました。
pipreqs . --encoding=utf-8 --force
# 以下是报错信息
ERROR: Failed on file: ./build.py
Traceback (most recent call last):
File "/usr/local/bin/pipreqs", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 528, in main
init(args)
File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 455, in init
candidates = get_all_imports(input_path,
File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 131, in get_all_imports
raise exc
File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 117, in get_all_imports
tree = ast.parse(contents)
File "/usr/lib/python3.8/ast.py", line 47, in parse
return compile(source, filename, mode, flags,
File "<unknown>", line 1
# -*- coding:utf-8 -*-
^
SyntaxError: invalid character in identifier
直接問い合わせてみるとSyntaxError
、#
無効な文字だったことが判明し、#
非常に無実であることを意味する文字であり、関係者は非常にショックを受けていました。!!これは世界を離れる素晴らしい兆候であり、世界に滑り込むという素晴らしい冗談ではありませんか?? ? これはたった 1 行のコード コメントですが、これが間違っているはずがありません。
2. 調査
初めてこの種の邪悪な現象に遭遇したとき、pipreqs
ソースコードを確認したところ、非常に単純なコードだったので、エラーが報告された部分を抜粋してみました。
# pipreqs/pipreqs.py line 112
for file_name in files:
file_name = os.path.join(root, file_name)
with open(file_name, "r", encoding=encoding) as f:
contents = f.read()
try:
tree = ast.parse(contents) # 在这里报错了
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for subnode in node.names:
raw_imports.add(subnode.name)
elif isinstance(node, ast.ImportFrom):
raw_imports.add(node.module)
except Exception as exc:
...
意味も分かりやすく、pipreqs
現在のプロジェクト配下のpython
ファイルを全て読み込み、ast
ライブラリを使って構文解析を行い、python
そのファイルが依存しているライブラリ名を取得します。この部分がエラーを報告していたので、直接取り出したのですが、この時点でast
何か重大な問題があるのではないかと疑いましたbug
。
3. 高エネルギー
ast
ファイルの解析にバグがあること を確認するために、python
現在のプロジェクト内のすべてのファイルを 1 つずつテストしましたが、予想を上回る展開となり、2 番目のファイルは(process_data.py)
解析できました。
このファイルを見てみると、冒頭に同じコメントがありましたが、エラーは報告されていませんでした。エンコードに問題があるのでしょうか?開けてPycharm
見てみましたが、特に問題はありませんでした。
これはあまりにも奇妙だったので、debug
もう一度チェックしてファイルの内容を調べて、何も問題がないことを確認しました。
理解できなかったので、次のように質問しましたChatGPT
。
疑問点は 4 つあり、基本的には 1 つずつ解消していきましたが、python 3.8
ファイルはutf-8
暗号化されており、文法的な誤りはなく、コメントにも問題はありませんでした。しかし、理解できないことが 1 つあります。それは、非表示の特殊文字ですか?
見えない?キャラクターなので、目に見えなくても場所があるはずです。その後、最も奇妙なことが起こりました。
これは、実際には最初の位置に null 文字があります。。。空の文字でもスペースを占有することはできますか?
を印刷してみるとASCII
、値は となっており65279
、空文字にも実はASCII
値が入っていたのですが、ふと、この問題は単純ではないのではないかと感じたのですが、本当に目に見えないのでしょうか?
4. 混乱を解消する
Baidu が調べたところ、ASCII
この値は65279
ファイルで使用されているエンコーディングによって引き起こされていることがわかりましたUTF-8 BOM
。これは、環境内でファイルを作成するときのデフォルトのエンコーディング方法ですWindows
。また、これを具体的に調べたところ、実際には次のとおりであることがわかりました。
にもこの設定がありますPycharm
。デフォルトでは、Pycharm
で新しいファイルを作成するときにエンコーディングが使用されます。UTF-8 with NO BOM
これはよく言われることですUTF-8
。一部のライブラリがファイルを正常に解析でき、一部のライブラリが解析できない理由は、一部のファイルがCreated inast
にない可能性があるためです。Pycharm
この奇妙な時間の出来事に。同時に、バイナリ モードでファイルを読み取ったところ、最初の 3 バイトが であることがわかりました\xEF\xBB\xBF
。これらはUTF-8 BOM
エンコード中に自動的に追加されました。
py_file = './build.py'
with open(py_file, 'r', encoding='utf-8') as f:
contents = f.read()
if ord(contents[0]) == 65279:
print('UTF-8 BOM')
with open(py_file, 'rb') as f:
contents = f.read(3)
if contents == b'\xEF\xBB\xBF':
print('UTF-8 BOM')
# UTF-8 BOM
# UTF-8 BOM
そこで、ファイルエンコーディングを から にUTF-8 BOM
変更したところUTF-8
、問題は解決しました。
WeChat 公開アカウントをフォローして、
夏小悠
より多くの記事、論文PPT
、その他の情報を入手してください ^_^