{
  "chapter": {
    "id": "fichiers-csv",
    "level": "premiere",
    "theme": "Données",
    "title": "Fichiers CSV",
    "description": "Format CSV (Comma Separated Values), séparateurs (virgule,\npoint-virgule, tabulation), lecture et écriture avec le\nmodule `csv`, en-tête, encodage UTF-8, conversion des\ntypes, manipulations courantes.",
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "definition"
      ],
      "title": "Que signifie CSV ?",
      "statement": "Que signifie l'acronyme **CSV** ?",
      "options": [
        {
          "text": "Comma Separated Values (valeurs séparées par des virgules)",
          "correct": true,
          "feedback": "Bonne réponse : c'est un format texte simple\ndans lequel chaque ligne est un enregistrement\net les champs sont séparés par un délimiteur\n(souvent une virgule, parfois un point-virgule\nou une tabulation).\n"
        },
        {
          "text": "Computer System Variables",
          "correct": false,
          "feedback": "Erreur : aucun rapport. C'est un format de\nfichier de données tabulaires.\n"
        },
        {
          "text": "Compressed Storage Vector",
          "correct": false,
          "feedback": "Erreur : CSV n'est pas un format compressé.\n"
        },
        {
          "text": "Centered Spreadsheet View",
          "correct": false,
          "feedback": "Erreur : ce n'est pas une vue de tableur, c'est\nun format texte.\n"
        }
      ],
      "explanation": "Le CSV est un standard très répandu pour les échanges\nde données entre tableurs, bases de données et\nprogrammes. Sa simplicité (texte brut, ligne par\nligne) en fait un format universel."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "structure"
      ],
      "title": "Structure d'un CSV",
      "statement": "Quelle est la structure de base d'un fichier CSV ?",
      "options": [
        {
          "text": "Un fichier XML structuré par balises",
          "correct": false,
          "feedback": "Erreur : CSV n'a pas de balises, juste des\nséparateurs.\n"
        },
        {
          "text": "Un format JSON imbriqué",
          "correct": false,
          "feedback": "Erreur : aucun rapport avec JSON. CSV est plat.\n"
        },
        {
          "text": "Un fichier texte où chaque ligne est un enregistrement et chaque champ est séparé par un délimiteur",
          "correct": true,
          "feedback": "Bonne réponse : la première ligne contient\nsouvent les noms des colonnes (en-tête), puis\nchaque ligne suivante représente une entrée du\njeu de données.\n"
        },
        {
          "text": "Un fichier binaire avec en-tête et indexation",
          "correct": false,
          "feedback": "Erreur : CSV est un format **texte**, pas\nbinaire. Il s'ouvre avec n'importe quel éditeur\nde texte.\n"
        }
      ],
      "explanation": "Exemple typique : la première ligne `nom,age,ville`\ndéfinit les colonnes ; les lignes suivantes\ncontiennent les valeurs correspondantes."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "separateurs"
      ],
      "title": "Séparateur en France",
      "statement": "Pourquoi en France utilise-t-on souvent le **point-virgule**\n`;` comme séparateur dans les fichiers CSV ?",
      "options": [
        {
          "text": "Parce que la norme ISO l'exige",
          "correct": false,
          "feedback": "Erreur : CSV n'est pas strictement normé. Le\nchoix du séparateur dépend des conventions\nlocales.\n"
        },
        {
          "text": "Parce que les fichiers seraient sinon trop volumineux",
          "correct": false,
          "feedback": "Erreur : aucun rapport avec la taille.\n"
        },
        {
          "text": "Parce que la virgule est utilisée comme séparateur décimal en français (par exemple `3,14`), ce qui crée un conflit",
          "correct": true,
          "feedback": "Bonne réponse : `1,5;Paris` est sans ambiguïté,\nmais `1,5,Paris` ne l'est pas (s'agit-il d'un\nou deux champs ?). Excel et LibreOffice en\nversion française utilisent donc `;` par défaut.\n"
        },
        {
          "text": "Parce que le point-virgule est plus rapide à taper",
          "correct": false,
          "feedback": "Erreur : ce n'est pas une raison de saisie.\n"
        }
      ],
      "explanation": "D'autres séparateurs sont possibles : tabulation\n(TSV), barre verticale `|`, etc. Le module `csv` de\nPython permet de spécifier le délimiteur via\n`delimiter=\";\"`."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "entete"
      ],
      "title": "Ligne d'en-tête",
      "statement": "À quoi sert la **première ligne** d'un fichier CSV ?",
      "options": [
        {
          "text": "Elle indique la taille du fichier",
          "correct": false,
          "feedback": "La taille d'un fichier\nse mesure en octets et\nse lit dans le système\nde fichiers, pas dans\nson contenu. L'en-tête\nd'un CSV donne les noms\ndes colonnes.\n"
        },
        {
          "text": "Elle contient toujours les données du premier enregistrement",
          "correct": false,
          "feedback": "Erreur : par convention, la première ligne\ncontient le plus souvent un **en-tête**, pas\ndes données.\n"
        },
        {
          "text": "Elle est obligatoirement vide",
          "correct": false,
          "feedback": "Erreur : au contraire, elle contient\ngénéralement les noms de colonnes.\n"
        },
        {
          "text": "Elle contient les noms des colonnes (en-tête)",
          "correct": true,
          "feedback": "Bonne réponse : c'est l'usage le plus répandu.\nLes programmes (et `csv.DictReader`) s'en\nservent pour donner un nom à chaque champ.\n"
        }
      ],
      "explanation": "L'en-tête est une **convention**, pas une\nobligation. Certains CSV n'en ont pas (par exemple\ndes exports machine sans description). Il faut alors\nle savoir avant de lire le fichier."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "extension"
      ],
      "title": "Extension de fichier",
      "statement": "Quelle est l'extension habituelle d'un fichier CSV ?",
      "options": [
        {
          "text": ".json",
          "correct": false,
          "feedback": "Erreur : JSON est un autre format de données\n(hiérarchique).\n"
        },
        {
          "text": ".txt",
          "correct": false,
          "feedback": "Erreur : techniquement possible (CSV est du\ntexte), mais l'extension conventionnelle est\ndifférente.\n"
        },
        {
          "text": ".csv",
          "correct": true,
          "feedback": "Bonne réponse : c'est l'extension standard,\nreconnue par les tableurs et les outils de\ntraitement de données.\n"
        },
        {
          "text": ".xlsx",
          "correct": false,
          "feedback": "Erreur : `.xlsx` est le format propriétaire\nd'Excel (binaire compressé), pas CSV.\n"
        }
      ],
      "explanation": "L'extension `.csv` est reconnue par Excel,\nLibreOffice Calc, Google Sheets et la plupart des\nlangages de programmation, qui peuvent\nautomatiquement proposer un import."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "lecture-simple"
      ],
      "title": "Lecture sans le module csv",
      "statement": "Sans utiliser le module `csv`, comment peut-on lire\nun fichier CSV simple en Python ?",
      "options": [
        {
          "text": "Avec `os.read()`",
          "correct": false,
          "feedback": "Erreur : c'est une fonction bas niveau qui\nretourne des octets bruts.\n"
        },
        {
          "text": "Avec `print('csv')`",
          "correct": false,
          "feedback": "Erreur : `print` affiche, ne lit pas.\n"
        },
        {
          "text": "Avec `open()` puis `.split(',')` sur chaque ligne",
          "correct": true,
          "feedback": "Bonne réponse : on ouvre le fichier en lecture\net on parcourt ligne par ligne, en séparant\nchaque ligne par le délimiteur. Cela marche\npour les CSV simples mais échoue avec les\nchamps contenant le délimiteur.\n"
        },
        {
          "text": "Avec `import json` et `json.load()`",
          "correct": false,
          "feedback": "Erreur : `json.load()` lit du JSON, pas du CSV.\n"
        }
      ],
      "explanation": "Cette approche a des limites : elle ne gère pas les\nchamps entre guillemets, les sauts de ligne dans\nles champs, ou les caractères d'échappement. Pour\ncela, mieux vaut le module `csv`."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "csv-module"
      ],
      "title": "Module standard",
      "statement": "Quel module de la bibliothèque standard de Python\nfacilite la manipulation des fichiers CSV ?",
      "options": [
        {
          "text": "`csv`",
          "correct": true,
          "feedback": "Bonne réponse : `import csv` donne accès aux\nfonctions `csv.reader`, `csv.writer`,\n`csv.DictReader`, `csv.DictWriter`.\n"
        },
        {
          "text": "`pandas`",
          "correct": false,
          "feedback": "`pandas` est très utilisé pour les CSV mais\nc'est une bibliothèque externe (pas standard).\nIl faut l'installer.\n"
        },
        {
          "text": "`numpy`",
          "correct": false,
          "feedback": "`numpy` peut lire des CSV via `genfromtxt`,\nmais ce n'est pas son rôle principal et c'est\négalement externe.\n"
        },
        {
          "text": "`xml.etree`",
          "correct": false,
          "feedback": "Erreur : ce module sert pour les fichiers XML.\n"
        }
      ],
      "explanation": "Le module `csv` fait partie de la bibliothèque\nstandard (livré avec Python). Aucune installation\nn'est nécessaire."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "encodage"
      ],
      "title": "Encodage recommandé",
      "statement": "Quel **encodage** est aujourd'hui recommandé pour les\nfichiers CSV ?",
      "options": [
        {
          "text": "ISO-8859-1 uniquement",
          "correct": false,
          "feedback": "Encodage ancien (Latin-1), encore courant en\nEurope mais limité à 256 caractères. À éviter\npour de nouveaux projets.\n"
        },
        {
          "text": "Binaire compressé",
          "correct": false,
          "feedback": "Erreur : un CSV est du texte, pas du binaire.\n"
        },
        {
          "text": "UTF-8",
          "correct": true,
          "feedback": "Bonne réponse : UTF-8 supporte tous les\ncaractères Unicode (français, chinois, emojis...).\nC'est l'encodage standard moderne.\n"
        },
        {
          "text": "ASCII pur",
          "correct": false,
          "feedback": "Erreur : ASCII ne couvre pas les caractères\naccentués (é, à, ç...), inutilisables en\nfrançais.\n"
        }
      ],
      "explanation": "En Python, on précise l'encodage à l'ouverture :\n`open(\"data.csv\", encoding=\"utf-8\")`. Si on omet\ncet argument, Python utilise l'encodage par défaut\ndu système, ce qui peut poser problème entre\nWindows et Linux."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "csv-reader"
      ],
      "title": "Itération avec csv.reader",
      "statement": "Que renvoie `csv.reader(f)` lorsqu'on l'utilise dans\nune boucle `for ligne in csv.reader(f):` ?",
      "options": [
        {
          "text": "Un dictionnaire `{nom_colonne: valeur}`",
          "correct": false,
          "feedback": "Erreur : c'est ce que renvoie `csv.DictReader`,\npas `csv.reader`.\n"
        },
        {
          "text": "Une chaîne de caractères pour chaque ligne",
          "correct": false,
          "feedback": "Erreur : pour avoir une chaîne, il suffirait\nde boucler directement sur le fichier `f`.\n"
        },
        {
          "text": "Un tuple immuable",
          "correct": false,
          "feedback": "Erreur : c'est une liste mutable.\n"
        },
        {
          "text": "Une liste des champs de chaque ligne",
          "correct": true,
          "feedback": "Bonne réponse : chaque itération produit une\nliste comme `[\"Alice\", \"17\", \"Lyon\"]`. Tous les\néléments sont des chaînes (il faut convertir\nsi l'on veut des entiers).\n"
        }
      ],
      "explanation": "Penser à convertir les valeurs numériques avec\n`int()` ou `float()` avant tout calcul. CSV est\ntexte : `\"17\" + 1` ne fonctionnera pas."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "ecriture"
      ],
      "title": "Écrire dans un CSV",
      "statement": "Quelle fonction du module `csv` permet d'**écrire**\ndans un fichier CSV ?",
      "options": [
        {
          "text": "`csv.save()`",
          "correct": false,
          "feedback": "Erreur : cette fonction n'existe pas.\n"
        },
        {
          "text": "`csv.put()`",
          "correct": false,
          "feedback": "Erreur : cette fonction n'existe pas.\n"
        },
        {
          "text": "`csv.writer()`",
          "correct": true,
          "feedback": "Bonne réponse : on l'utilise avec un fichier\nouvert en écriture (`\"w\"`), puis sa méthode\n`.writerow()` ou `.writerows()` ajoute les\nlignes.\n"
        },
        {
          "text": "`csv.write()`",
          "correct": false,
          "feedback": "Erreur : cette fonction n'existe pas.\n"
        }
      ],
      "explanation": "Schéma typique :\n`with open(\"out.csv\", \"w\", newline=\"\", encoding=\"utf-8\") as f:`\n`    w = csv.writer(f) ; w.writerow([\"a\", \"b\"])`."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "dictreader"
      ],
      "title": "Différence reader / DictReader",
      "statement": "Quelle est la différence entre `csv.reader` et\n`csv.DictReader` ?",
      "options": [
        {
          "text": "`DictReader` lit plus vite",
          "correct": false,
          "feedback": "Erreur : la performance n'est pas la\ndifférence essentielle.\n"
        },
        {
          "text": "`reader` n'existe pas en Python 3",
          "correct": false,
          "feedback": "Erreur : il existe parfaitement.\n"
        },
        {
          "text": "`reader` produit des listes, `DictReader` produit des dictionnaires indexés par les noms de colonnes (lus depuis l'en-tête)",
          "correct": true,
          "feedback": "Bonne réponse : `DictReader` consomme la\npremière ligne comme en-tête et permet\nensuite d'écrire `ligne[\"nom\"]` au lieu de\n`ligne[0]`. Plus lisible et robuste si l'ordre\ndes colonnes change.\n"
        },
        {
          "text": "`DictReader` ignore l'en-tête",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse, il **utilise**\nl'en-tête pour nommer les colonnes.\n"
        }
      ],
      "explanation": "`DictReader` est généralement préférable quand le\nfichier a un en-tête : le code est plus auto-documenté\n(`ligne[\"age\"]` plutôt que `ligne[2]`)."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "conversion-types"
      ],
      "title": "Conversion de types",
      "statement": "Après lecture, on obtient `ligne = [\"Alice\", \"17\"]`.\nComment obtenir un âge utilisable comme nombre ?",
      "options": [
        {
          "text": "`age = int(ligne[1])`",
          "correct": true,
          "feedback": "Bonne réponse : `int()` convertit la chaîne\n`\"17\"` en entier `17`, utilisable dans des\ncalculs.\n"
        },
        {
          "text": "`age = list(ligne[1])`",
          "correct": false,
          "feedback": "Erreur : `list(\"17\")` donne `['1', '7']`, pas\nun entier.\n"
        },
        {
          "text": "`age = ligne[1].number()`",
          "correct": false,
          "feedback": "Erreur : la méthode `.number()` n'existe pas\nsur les chaînes.\n"
        },
        {
          "text": "`age = ligne[1]`",
          "correct": false,
          "feedback": "Erreur : `age` reste une **chaîne**. Faire\n`age + 1` lèverait `TypeError`.\n"
        }
      ],
      "explanation": "Toujours convertir explicitement : `int()`,\n`float()`, `bool()` selon le besoin. Penser aussi\nau cas où la cellule est vide (chaîne `\"\"`), qui\nprovoquerait `ValueError` avec `int()`."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "delimiter"
      ],
      "title": "Spécifier le séparateur",
      "statement": "Comment lire un CSV utilisant le **point-virgule**\ncomme séparateur avec le module `csv` ?",
      "options": [
        {
          "text": "`csv.reader(f).set_separator(';')`",
          "correct": false,
          "feedback": "Erreur : cette méthode n'existe pas.\n"
        },
        {
          "text": "`csv.reader(f, delimiter=';')`",
          "correct": true,
          "feedback": "Bonne réponse : on précise le délimiteur via\nl'argument nommé `delimiter`.\n"
        },
        {
          "text": "`csv.reader_semicolon(f)`",
          "correct": false,
          "feedback": "Erreur : cette fonction n'existe pas.\n"
        },
        {
          "text": "`csv.reader(f)` (suffisant, le module détecte tout seul)",
          "correct": false,
          "feedback": "Erreur : par défaut, le séparateur est la\nvirgule. Le module ne devine pas (il existe\n`csv.Sniffer` mais ce n'est pas automatique).\n"
        }
      ],
      "explanation": "Pour les fichiers exportés par Excel français, le\nséparateur est `;`. Pour les CSV anglo-saxons ou\nGoogle Sheets, c'est `,`. Pour TSV (tab-separated),\nc'est `'\\t'`."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "guillemets"
      ],
      "title": "Champs contenant le séparateur",
      "statement": "Comment représente-t-on un champ contenant le\ncaractère séparateur (par exemple une virgule) dans\nun CSV à séparateur virgule ?",
      "options": [
        {
          "text": "On échappe la virgule avec un antislash `\\,`",
          "correct": false,
          "feedback": "Erreur : ce n'est pas la convention CSV\nstandard (qui utilise les guillemets).\n"
        },
        {
          "text": "On supprime la virgule du champ",
          "correct": false,
          "feedback": "Erreur : on perdrait l'information.\n"
        },
        {
          "text": "On change le séparateur pour ce champ uniquement",
          "correct": false,
          "feedback": "Erreur : un fichier CSV utilise un séparateur\nunique pour tout le fichier.\n"
        },
        {
          "text": "On entoure le champ de guillemets doubles : `\"Lyon, France\"`",
          "correct": true,
          "feedback": "Bonne réponse : c'est la convention RFC 4180.\nLe module `csv` gère cette syntaxe\nautomatiquement (lecture comme écriture).\n"
        }
      ],
      "explanation": "Et pour un guillemet à l'intérieur d'un champ\n« guillemeté » ? On le double : `\"il dit \"\"bonjour\"\"\"`."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "trace-lecture"
      ],
      "title": "Trace de lecture",
      "statement": "Le fichier `eleves.csv` contient :\n```\nnom;age\nAlice;17\nBob;16\n```\nQue vaut `ligne` au premier passage de la boucle\n`for ligne in csv.DictReader(open(\"eleves.csv\"), delimiter=\";\")` ?",
      "options": [
        {
          "text": "`['Alice', '17']`",
          "correct": false,
          "feedback": "Erreur : ce serait le retour de `csv.reader`,\npas de `csv.DictReader`.\n"
        },
        {
          "text": "`['nom', 'age']`",
          "correct": false,
          "feedback": "Erreur : `DictReader` consomme la première\nligne comme en-tête, elle n'apparaît pas dans\nla boucle.\n"
        },
        {
          "text": "`{'nom': 'Alice', 'age': '17'}`",
          "correct": true,
          "feedback": "Bonne réponse : `DictReader` saute l'en-tête\net associe chaque valeur à son nom de colonne.\nNoter que `'17'` reste une chaîne.\n"
        },
        {
          "text": "`{'Alice': '17', 'Bob': '16'}`",
          "correct": false,
          "feedback": "Erreur : on ne reçoit qu'une ligne à chaque\nitération, pas tout le fichier.\n"
        }
      ],
      "explanation": "Pour récupérer toutes les lignes d'un coup :\n`lignes = list(csv.DictReader(...))`."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "filtrage"
      ],
      "title": "Filtrer les données",
      "statement": "Comment afficher seulement les élèves de plus de\n16 ans à partir d'un CSV `nom,age` lu via\n`csv.DictReader` ?",
      "options": [
        {
          "text": "```python\nfor ligne in lecteur:\n    print(ligne[\"nom\"]) if ligne[\"age\"] > 16\n```\n",
          "correct": false,
          "feedback": "Erreur : syntaxe Python invalide (le `if`\nternaire requiert un `else`) **et** problème\nde type.\n"
        },
        {
          "text": "```python\nlecteur.filter(age > 16)\n```\n",
          "correct": false,
          "feedback": "Erreur : la méthode `.filter()` n'existe pas\nsur `csv.DictReader`. C'est une syntaxe d'un\nautre langage (SQL ?).\n"
        },
        {
          "text": "```python\nfor ligne in lecteur:\n    if ligne[\"age\"] > 16:\n        print(ligne[\"nom\"])\n```\n",
          "correct": false,
          "feedback": "Erreur : `ligne[\"age\"]` est une **chaîne**\n(`\"17\"`). En Python 3, comparer une chaîne et\nun entier lève `TypeError`.\n"
        },
        {
          "text": "```python\nfor ligne in lecteur:\n    if int(ligne[\"age\"]) > 16:\n        print(ligne[\"nom\"])\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : on convertit l'âge en entier\n(sinon `\"17\" > 16` est invalide en Python 3),\non filtre, on affiche le nom.\n"
        }
      ],
      "explanation": "Toujours convertir avant de comparer\nnumériquement. Pour des manipulations plus\ncomplexes, `pandas` est plus pratique mais c'est\nhors programme."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "newline-windows"
      ],
      "title": "Argument newline=''",
      "statement": "Pourquoi écrit-on souvent\n`open(\"data.csv\", \"w\", newline=\"\", encoding=\"utf-8\")`\npour écrire un CSV ?",
      "options": [
        {
          "text": "Pour ajouter une ligne d'en-tête automatiquement",
          "correct": false,
          "feedback": "Erreur : `newline=\"\"` n'a aucun effet sur\nl'en-tête. Il faut écrire l'en-tête\nexplicitement.\n"
        },
        {
          "text": "Pour rendre le fichier illisible par les humains",
          "correct": false,
          "feedback": "Erreur : un CSV reste un fichier texte\nparfaitement lisible.\n"
        },
        {
          "text": "Pour éviter d'insérer des lignes vides entre chaque enregistrement sous Windows (problème classique de gestion des fins de ligne)",
          "correct": true,
          "feedback": "Bonne réponse : sans `newline=\"\"`, Python\nréécrit `\\n` → `\\r\\n` sur Windows, et le\nmodule `csv` ajoute lui-même un `\\r\\n`,\nprovoquant des doubles sauts. La solution\nrecommandée par la doc est `newline=\"\"`.\n"
        },
        {
          "text": "Pour augmenter les performances",
          "correct": false,
          "feedback": "Erreur : ce n'est pas une question de\nperformance.\n"
        }
      ],
      "explanation": "Petit détail technique mais essentiel pour la\nportabilité Linux/macOS/Windows. À ajouter\nsystématiquement quand on utilise `csv.writer`."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "valeurs-manquantes"
      ],
      "title": "Valeurs manquantes",
      "statement": "Dans un CSV avec `nom,age,ville` et la ligne\n`Alice,,Lyon`, que vaut `ligne[\"age\"]` après lecture\npar `csv.DictReader` ?",
      "options": [
        {
          "text": "Le programme lève une exception",
          "correct": false,
          "feedback": "Erreur : la lecture se passe sans erreur ;\nc'est seulement la conversion ultérieure\n(`int(\"\")`) qui lèverait `ValueError`.\n"
        },
        {
          "text": "`0`",
          "correct": false,
          "feedback": "Erreur : le module ne fait aucune supposition.\nUne absence n'est pas un zéro.\n"
        },
        {
          "text": "`None`",
          "correct": false,
          "feedback": "Erreur : `csv.DictReader` ne convertit pas\nautomatiquement les vides en `None`.\n"
        },
        {
          "text": "`''` (chaîne vide)",
          "correct": true,
          "feedback": "Bonne réponse : un champ vide entre deux\nséparateurs est lu comme une chaîne vide. Il\nfaut le tester explicitement avant toute\nconversion : `if ligne[\"age\"] != \"\":`.\n"
        }
      ],
      "explanation": "Donnée manquante : penser à filtrer ou utiliser\nune valeur par défaut, par exemple\n`int(ligne[\"age\"]) if ligne[\"age\"] else None`."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "export-tableur"
      ],
      "title": "Export depuis tableur",
      "statement": "Quelle situation correspond à un cas d'usage typique\ndu format CSV ?",
      "options": [
        {
          "text": "Échanger un tableau de notes entre Pronote, un tableur et un script Python",
          "correct": true,
          "feedback": "Bonne réponse : c'est exactement le rôle du\nCSV, un format pivot universel pour les\ndonnées tabulaires, lisible par tous les\noutils.\n"
        },
        {
          "text": "Stocker une vidéo HD",
          "correct": false,
          "feedback": "Erreur : CSV est un format texte, inadapté à\nla vidéo (binaire compressé).\n"
        },
        {
          "text": "Construire une page web interactive",
          "correct": false,
          "feedback": "Erreur : c'est le rôle du HTML/CSS/JS.\n"
        },
        {
          "text": "Programmer un microcontrôleur",
          "correct": false,
          "feedback": "Erreur : on programme en C, Python, etc., pas\nen CSV.\n"
        }
      ],
      "explanation": "Force du CSV : universalité. Faiblesses : pas de\ntypes (tout est texte), pas de hiérarchie, pas de\nschéma standard (séparateur, encodage variables)."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "comparaison-formats"
      ],
      "title": "CSV vs JSON",
      "statement": "Pour stocker une **liste plate de personnes**\n(nom, âge, ville), CSV ou JSON ?",
      "options": [
        {
          "text": "JSON est obligatoire dès qu'on programme",
          "correct": false,
          "feedback": "Erreur : aucune obligation. Chaque format a\nses cas d'usage.\n"
        },
        {
          "text": "CSV est le plus adapté car les données sont tabulaires et plates",
          "correct": true,
          "feedback": "Bonne réponse : pour des données strictement\ntabulaires, CSV est plus compact et plus\nrapide à parser. JSON brille pour les\nstructures hiérarchiques (données imbriquées,\nlistes de listes).\n"
        },
        {
          "text": "Aucun, il faut une base de données",
          "correct": false,
          "feedback": "Exagéré : pour quelques centaines de lignes,\nun fichier CSV est largement suffisant.\n"
        },
        {
          "text": "XML est toujours le bon choix",
          "correct": false,
          "feedback": "Erreur : XML est verbeux pour des données\nplates ; on lui préfère CSV ou JSON.\n"
        }
      ],
      "explanation": "Règle pratique : **plat et tabulaire → CSV** ;\n**hiérarchique → JSON** ; **gros volumes ou\nrequêtes complexes → SGBD**."
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "debug-encodage"
      ],
      "title": "Bug d'encodage",
      "statement": "Un élève lit un CSV créé sous Windows et obtient\n`Café` au lieu de `Café`. Quelle est la cause la\nplus probable ?",
      "options": [
        {
          "text": "Python est trop ancien pour gérer l'UTF-8",
          "correct": false,
          "feedback": "Erreur : Python 3 gère parfaitement UTF-8\ndepuis sa sortie.\n"
        },
        {
          "text": "Le fichier est corrompu",
          "correct": false,
          "feedback": "Erreur : le contenu est correct, c'est\nl'**interprétation** de l'encodage qui pose\nproblème.\n"
        },
        {
          "text": "Le fichier est encodé en UTF-8 mais lu comme du Latin-1 (ISO-8859-1)",
          "correct": true,
          "feedback": "Bonne réponse : `é` en UTF-8 = `0xC3 0xA9`. Lu\ncomme Latin-1, ces deux octets donnent `Ã©`.\nSolution : préciser `encoding=\"utf-8\"` à\nl'ouverture.\n"
        },
        {
          "text": "La connexion internet est instable",
          "correct": false,
          "feedback": "Erreur : aucun rapport, on lit un fichier\nlocal.\n"
        }
      ],
      "explanation": "Indice révélateur : `é` = `Ã©` est la **signature\nclassique** d'une mauvaise interprétation d'UTF-8\nen Latin-1. Il existe d'autres signatures\n(`’` au lieu de `’`) qui pointent vers le même\nproblème."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "parsing-piege"
      ],
      "title": "Parsing à la main",
      "statement": "Pourquoi `ligne.split(',')` est-il **insuffisant**\npour parser correctement la ligne CSV\n`\"Doe, John\",42,\"Lyon, France\"` ?",
      "options": [
        {
          "text": "`split` ne fonctionne que sur des fichiers UTF-8",
          "correct": false,
          "feedback": "Erreur : `split` est indépendant de l'encodage.\n"
        },
        {
          "text": "`split` modifie le fichier d'origine",
          "correct": false,
          "feedback": "Erreur : `split` ne modifie rien, il renvoie\nune nouvelle liste.\n"
        },
        {
          "text": "`split` ne respecte pas les guillemets et coupe à chaque virgule, donnant 5 champs au lieu de 3",
          "correct": true,
          "feedback": "Bonne réponse : `split(',')` produit `['\\\"Doe',\n' John\\\"', '42', '\\\"Lyon', ' France\\\"']`. Le\nmodule `csv` gère correctement ce cas en\nregroupant les champs entourés de guillemets.\n"
        },
        {
          "text": "`split` est trop lent",
          "correct": false,
          "feedback": "Erreur : la performance n'est pas le\nproblème, la **correction** l'est.\n"
        }
      ],
      "explanation": "Leçon : pour tout CSV non trivial (guillemets,\nsauts de ligne dans les champs, échappements),\nutiliser le module `csv`. Le « parsing manuel »\nn'est correct que pour des cas très simples et\nmaîtrisés."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "statistiques"
      ],
      "title": "Calcul d'une moyenne",
      "statement": "Le fichier `notes.csv` contient une colonne `note`\n(entête en première ligne) avec des nombres entiers.\nQuel code calcule correctement la **moyenne** ?",
      "options": [
        {
          "text": "```python\nmoyenne = csv.mean(\"notes.csv\", \"note\")\n```\n",
          "correct": false,
          "feedback": "Erreur : la fonction `csv.mean` n'existe pas.\nLe module `csv` se limite à la lecture/écriture.\n"
        },
        {
          "text": "```python\nwith open(\"notes.csv\") as f:\n    moyenne = sum(csv.reader(f)) / 2\n```\n",
          "correct": false,
          "feedback": "Erreur : `sum` ne sait pas additionner des\nlistes de chaînes ; et la division par 2 est\narbitraire.\n"
        },
        {
          "text": "```python\nwith open(\"notes.csv\") as f:\n    total = 0\n    for ligne in csv.DictReader(f):\n        total += ligne[\"note\"]\n    moyenne = total / len(lignes)\n```\n",
          "correct": false,
          "feedback": "Erreur : `ligne[\"note\"]` est une **chaîne**.\n`total += \"12\"` lève `TypeError`. De plus\n`lignes` n'est pas défini.\n"
        },
        {
          "text": "```python\nwith open(\"notes.csv\") as f:\n    notes = [int(ligne[\"note\"]) for ligne in csv.DictReader(f)]\nmoyenne = sum(notes) / len(notes)\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : on construit une liste\nd'entiers (conversion explicite avec `int`),\npuis `sum / len`. Code concis et correct.\n"
        }
      ],
      "explanation": "Trois étapes systématiques : ouvrir, convertir\nles types, calculer. Toujours penser à la\nconversion en numérique avant tout calcul."
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "ecriture-complete"
      ],
      "title": "Écrire avec en-tête",
      "statement": "Quel code écrit correctement un CSV avec en-tête à\npartir d'une liste de tuples\n`donnees = [(\"Alice\", 17), (\"Bob\", 16)]` ?",
      "options": [
        {
          "text": "```python\ncsv.write(\"out.csv\", donnees)\n```\n",
          "correct": false,
          "feedback": "Erreur : la fonction `csv.write` n'existe\npas. Il faut un objet `writer`.\n"
        },
        {
          "text": "```python\nwith open(\"out.csv\", \"w\") as f:\n    f.write(donnees)\n```\n",
          "correct": false,
          "feedback": "Erreur : `write` attend une **chaîne**, pas\nune liste de tuples.\n"
        },
        {
          "text": "```python\nwith open(\"out.csv\", \"w\") as f:\n    for nom, age in donnees:\n        f.write(nom + \",\" + age + \"\\n\")\n```\n",
          "correct": false,
          "feedback": "Erreur : `age` est un entier, on ne peut pas\nle concaténer à une chaîne avec `+` (TypeError).\nEt l'en-tête est absent. Et `newline=\"\"`\nmanquant pour un usage portable.\n"
        },
        {
          "text": "```python\nwith open(\"out.csv\", \"w\", newline=\"\", encoding=\"utf-8\") as f:\n    w = csv.writer(f)\n    w.writerow([\"nom\", \"age\"])\n    w.writerows(donnees)\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : `writerow` pour l'en-tête,\n`writerows` (avec `s`) pour la liste de tuples\n; `newline=\"\"` pour la portabilité ;\n`encoding=\"utf-8\"` pour les accents. Code\nidiomatique et robuste.\n"
        }
      ],
      "explanation": "Bonne pratique systématique : `with open(...,\nnewline=\"\", encoding=\"utf-8\")` + `csv.writer` +\n`writerow` (en-tête) + `writerows` (données)."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Limite du CSV",
      "statement": "Parmi les affirmations suivantes sur le format CSV,\nlaquelle est **fausse** ?",
      "options": [
        {
          "text": "CSV impose une typage explicite des colonnes (entier, flottant, date)",
          "correct": true,
          "feedback": "Faux (donc bonne réponse) : tout est traité\ncomme du **texte** dans un CSV. Aucun type\nn'est conservé. C'est au programme de lecture\nde convertir explicitement.\n"
        },
        {
          "text": "CSV ne gère pas nativement les structures hiérarchiques (listes imbriquées, dictionnaires)",
          "correct": false,
          "feedback": "Vrai : c'est sa principale limite par rapport\nà JSON ou XML.\n"
        },
        {
          "text": "CSV est un format texte, lisible avec n'importe quel éditeur",
          "correct": false,
          "feedback": "Vrai : c'est l'un de ses grands avantages.\n"
        },
        {
          "text": "Le séparateur n'est pas standardisé universellement (virgule, point-virgule, tabulation...)",
          "correct": false,
          "feedback": "Vrai : c'est une faiblesse historique du\nformat. La RFC 4180 propose la virgule mais\nn'est pas suivie partout.\n"
        }
      ],
      "explanation": "Limites du CSV : pas de typage, pas de hiérarchie,\nséparateur variable, encodage variable. Pour des\ndonnées complexes ou critiques, on lui préfère\nJSON, Parquet, ou une vraie base de données."
    }
  ]
}