Visual Studio用。 UTF-8 BOMなしの場合は、/source-charset:utf-8
をつけておかないと、エライことになると同僚から報告を受けた。この話は後述する。
なので、可能な限りUTF-8 with BOMに自動で変換してみる。以下のコードを実行する前に必ずバックアップを取っておくか、変換するコードはコメントアウトして実行すること(重要)。
import chardet import glob # 探索する拡張子リスト extensions = ["cpp", "hpp", "c", "h", "cxx", "hxx"] def check(filename): # バイナリで開く with open(filename, 'rb') as f: b = f.read() # 文字コードを検出(Shift-JISへの精度は高くない) det_chardet = chardet.detect(b) # UTF-8 with BOM以外の場合はprint if det_chardet["encoding"] != "UTF-8-SIG": print(det_chardet, filename) # ascii100%のコードをUTF-8 with BOMへ変換 if det_chardet["encoding"] == "ascii" and det_chardet["confidence"] == 1.0: with open(filename) as f: contents = f.read() with open(filename, "w", encoding="utf_8_sig") as f: f.write(contents) print("ascii -> UTF-8-SIG") # SHIFT_JIS(と何故か間違えられやすいWindows-1252)のコードをUTF-8 with BOMへ変換 if det_chardet["encoding"] == "SHIFT_JIS" or det_chardet["encoding"] == "Windows-1252": with open(filename, "r", encoding="shift-jis") as f: contents = f.read() with open(filename, "w", encoding="utf_8_sig") as f: f.write(contents) print("SHIFT_JIS -> UTF-8-SIG") return det_chardet["encoding"] # エンコードリスト encodings = {} for extension in extensions: # cd以下全部を再帰的に探索 files = glob.glob(f"**/*.{extension}", recursive=True) for filename in files: # パッケージフォルダ内は無視する if "\\packages\\" in filename: continue det_encoding = check(filename) # 検出したエンコードリストを辞書型で集計する if det_encoding not in encodings: encodings[det_encoding] = 1 else: encodings[det_encoding] += 1 print() # 集計結果 print(encodings)
そもそもの発端である同僚からの報告を簡単に書いておく。
UTF-8 BOMなしのコードは、VCのコンパイラからはSHIFT-JISと推定される。UTF-8で書いていたコードのコメント行の末尾が文字化けし、以下のような例で
//コメント if() { }
が、
//コメントif() { }
と認識されてしまい{}内が常に実行されるという問題が発生したとのこと。仕様上仕方がない(バグではない)ので、気をつけるしかない。