aaiuk
@aaiuk

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

SyntaxError: invalid non-printable character U+FEFF こちらを直したいです。

解決したいこと

Visual Studio Codeで、Todoリストを作っています。
ある日突然、以下のエラーが発生し実行できなくなってしまったので、解決したいです。

発生している問題・エラー

エラーコードは下記のものですが、このエラーコードのimport jsonがそもそも94行目になく、一行目にしかありません。

  File "TodoList.py", line 94
    import json
    ^
SyntaxError: invalid non-printable character U+FEFF

調べて分かったこと

どうもBOMというものがファイルのまえに付属しているかしていないかで変わるようです。ただ、Visual StudioCodeのエンコードを変更してもエラーは治りませんでした。

該当するソースコード

エラーコードで指定された部分が存在しないので、全部置いておきます。

import json

class ToDoList:
    #todoリストの各機能を関数化したもの。裏で動く類の機能が集められている
    #クラスToDoListの関数が動くたびに実行されるもの
    def __init__(self, filename='todo_list.json'):
        self.filename=filename
        self.load_tasks()
        
    #タスクを読み込む。__init__にて実行されるため、直接呼び出すことはない。
    def load_tasks(self):
        try:
            with open(self.filename, 'r') as file:
                self.tasks = json.load(file)
        except FileNotFoundError:
            self.tasks = []
            
    #タスクをjsonファイルに保存する
    def save_tasks(self):
        with open(self.filename, 'w') as file:
            json.dump(self.tasks, file, indent=4)
            
    #タスクを追加する。全てのタスクが保存されている変数の末尾に、新規のタスクを追加する。
    def add_task(self, task):
        self.tasks.append({'task': task, 'completed': False})
        self.save_tasks()
        print(f"Task '{task}' added.")
        
    #タスクの一覧を番号付きで表示する。この番号は、保存されている変数の中で何番目の要素かに依存する。
    #また、各タスクが完了しているかも表示される。完了しているならば✓、完了していないならば×とそれぞれのタスクの横に表示される。    
    def show_tasks(self):
        if not self.tasks:
            print("No tasks in the List.")
            return
        for idx, task in enumerate(self.tasks, start=1):
            status = '' if task['completed'] else '×'
            print(f"{idx}.[{status}]{task['task']}")
    
    #指定された番号のタスクを削除する。もし指定された番号のタスクが存在しない場合はエラーメッセージを出力する。
    def delete_task(self, task_number):
        if 0 < task_number <= len(self.tasks):
            task = self.tasks.pop(task_number - 1)
            self.save_tasks()
            print(f"Task '{task['task']}' deleted.")
        else:
            print("invalid task number.")
    
    #指定された番号のタスクを完了という状態にする。
    def complete_task(self, task_number):
        if 0 < task_number <= len(self.tasks):
            self.tasks[task_number - 1]['completed'] = True
            self.save_tasks()
            print(f"Task '{self.tasks[task_number - 1]['task']}' marked as completed.")
        else:
            print("Invalid task number.")
    
    #指定された番号のタスクを未完了にする。
    def incomplete_task(self, task_number):
        if 0<task_number <= len(self.tasks):
            self.tasks[task_number - 1]['completed'] = False
            self.save_tasks()
            print(f"Task '{self.tasks[task_number - 1]['task']}' marked as incompleted.")
        else:
            print("Invalid task number.")

def main():
        todo_list = ToDoList()
        
        while True:
            print("\nToDo List:")
            todo_list.show_tasks()
            print("\nCommand: add [task], delete [task_number], complete [task_number], incomplete[task_number], quit")
            command = input("Enter command: ").strip().split(maxsplit=1)
            
            if not command:
                continue
            
            action = command[0].lower()
            
            #打ち込まれたコマンドを解釈して、動かすよ!各コマンドの詳細はクラスToDoListと本文を読んでね
            if action == 'add' and len(command) > 1:
                todo_list.add_task(command[1])
            elif action == 'delete' and len(command) > 1:
                try:
                    task_number = int(command[1])
                    todo_list.delete_task(task_number)
                except ValueError:
                    print("Invalid task number.")
            elif action == 'complete' and len(command) > 1:
                try:
                    task_number = int(command[1])
                    todo_list.complete_task(task_number)
                except ValueError:
                    print("Invalid task number.")
            elif action == 'incomplete' and len(command) > 1:
                try:
                    task_number = int(command[1])
                    todo_list.incomplete_task(task_number)
                except ValueError:
                    print("Invalid task number.")
            elif action == 'quit':
                break
            else:
                print("Invalid command.")

#実行するよ!(__name__が下記のif文の状態なら何かエラーがあるか、他のアプリに干渉されている可能性があるから動かさないよ)
if __name__ == "__main__":
    main()
0

3Answer

そのファイルをVSCodeで開くと、画面の右下の文字コードは UTF-8 with BOMでしょうか?

VSCodeのファイル種別で、(↓メニューの先頭)BOM無しのUTF-8を選択して、保存してみたらどうでしょうか?

scr1.png

1Like

「vscode bom なし保存」をキーワードに検索すると色々出てくるので一旦自力解決を試みてください。

0Like

SyntaxError: invalid non-printable character U+FEFF

BOM は以下のようになるので、上のエラーメッセージの U+FEFF が BOM だとすると文字コードは UTF-16BE ということになって、UTF-16 であれば BOM は必須だし、そもそも UTF-16 というのが変では?

UTF-8: EF BB BF
UTF-16BE: FE FF
UTF-16LE: FF FE
UTF-32BE: 00 00 FE FF
UTF-32LE: FF FE 00 00

0Like

Comments

  1. Unicode文字としては確かにU+FEFFの表現なのですが,これがUTF-8エンコードとしてバイトに書き込まれたものがEF-BB-BFになります.U+の表記は実バイト列の表現ではありません.参考までに.

  2. @Verclene さん

    BOM 付き UTF-8 のファイルと読み込もうとした結果が「SyntaxError: invalid non-printable character U+FEFF」と言ってますか? そうかもしれませんが、その確証はありますか?

  3. 中途半端な知識と状況整理でUTF-16の線(=状況があまりにも現実的でない)を追うような方にしかもその確証はありますかとか訊かれてもこちらも困ると言っています.ちなみにUTF-16なファイルをインタプリタに読ませようとするとSyntaxError: Non-UTF-8 code starting with '\xff' in みたいなことが出るので状況はさらに変わり得ます.

    本題のUTF-8についてですが,インタプリタ自体は先頭BOMを無視するようですが他のどこがしかでは事例があります.詳細な原因については環境を洗い出すしかありませんが,いずれにせよ現状対処としてはBOMを確実に取り除くしかありません.

  4. 確証はないということと理解します。

Your answer might help someone💌