ソースを参照

Fichiers texte : les « � » déjà présents ne comptent plus comme des octets invalides

Pour choisir entre la lecture en Windows-1252 et la lecture mélangée,
_decode_invalid_utf8 comptait les « � » du décodage tolérant. Les vrais
U+FFFD déjà enregistrés dans le fichier (un journal abîmé auparavant, par
exemple) étaient comptés comme des octets invalides : un fichier UTF-8 avec
quelques « � », des accents et un seul octet invalide était relu en entier
en Windows-1252 (« Café »).

Les U+FFFD présents dans les données (EF BF BD, toujours décodés d'un bloc)
sont maintenant retirés du compte. L'entrée du CHANGELOG précise que seul
un fichier surtout en UTF-8 est lu en mélangé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Johnounet 23 時間 前
親
コミット
7417cfb801
3 ファイル変更、8 行追加、2 行削除
  1. 1 1
      CHANGELOG.md
  2. 2 1
      bot/text_files.py
  3. 5 0
      tests/test_attachments_prep.py

+ 1 - 1
CHANGELOG.md

@@ -20,7 +20,7 @@ Les versions les plus récentes sont en haut. Chaque entrée commence par un ré
 
 - **Les grandes images en gris 16 bits ne deviennent plus toutes blanches.** Un scan, une radio ou une photo d'astronomie en PNG ou TIFF 16 bits (ou 32 bits), une fois réduit, arrivait tout blanc ou tout noir chez Claude. Ses gris sont maintenant ramenés sur 8 bits sans être écrêtés (Pillow 11 ou plus, installé avec les autres dépendances).
 
-- **Un octet abîmé ne déforme plus tous les accents d'un fichier texte.** Dans un `.txt`, `.log` ou `.csv` en UTF-8, un seul octet invalide faisait lire tout le fichier en Windows-1252 (« Café »). Seul cet octet est maintenant relu ainsi ; les fichiers « ANSI » et les fichiers mélangés restent bien lus.
+- **Un octet abîmé ne déforme plus tous les accents d'un fichier texte.** Dans un `.txt`, `.log` ou `.csv` en UTF-8, un seul octet invalide faisait lire tout le fichier en Windows-1252 (« Café »). Seul cet octet est maintenant relu ainsi, si le fichier est surtout en UTF-8 ; les fichiers « ANSI » restent bien lus.
 
 ---
 

+ 2 - 1
bot/text_files.py

@@ -44,7 +44,8 @@ def _decode_invalid_utf8(data: bytes) -> str:
     """
     if not data.startswith(codecs.BOM_UTF8):
         lenient = data.decode("utf-8", errors="replace")  # un « � » par suite d'octets invalides
-        invalid = lenient.count("�")
+        # Sans les « � » déjà dans le fichier (EF BF BD est toujours décodé d'un bloc).
+        invalid = lenient.count("�") - data.count("�".encode("utf-8"))
         valid = sum(1 for char in lenient if char > "\x7f") - invalid
         if invalid >= valid:
             return data.decode("cp1252", errors="replace")

+ 5 - 0
tests/test_attachments_prep.py

@@ -475,6 +475,11 @@ class DecodeTextFileTest(unittest.TestCase):
         data = codecs.BOM_UTF8 + "Été".encode("utf-8") + b" \xe9\xe9"
         self.assertEqual(decode_text_file(data), "Été éé")
 
+    def test_utf8_with_real_replacement_characters(self):
+        # Les « � » déjà présents (journal abîmé auparavant) ne comptent pas comme des octets invalides.
+        data = ("Café élève déjà " + "�" * 5 + " fin ").encode("utf-8") + b"\xe9"
+        self.assertEqual(decode_text_file(data), "Café élève déjà " + "�" * 5 + " fin é")
+
     def test_utf8_cut_in_the_middle_of_a_character(self):
         # Seul le caractère coupé est abîmé, le reste du texte garde ses accents.
         data = "Café ".encode("utf-8") + "é".encode("utf-8")[:1] + " à bientôt".encode("utf-8")