6 girdi → 3 kabul · 1 tekrar · 2 inceleme
U001 · İstanbul · giriş
U002 · Ankara · atölye
U004 · İzmir · atölye
GİRDİ, ÇIKTI VE KAYNAK KODU
Bu oturumda üretilen çıktı; veriler kurmacadır.
GİRDİ
katilimci_kodu;sehir;etkinlik
u001 ; istanbul ; giriş
U002;ANKARA;atölye
U001;İstanbul;giriş
U003;;giriş
U004;İZMİR;atölye
U005;Bursa;giriş
TEMİZ ÇIKTI
katilimci_kodu;sehir;etkinlik
U001;İstanbul;giriş
U002;Ankara;atölye
U004;İzmir;atölye
SAYIM RAPORU
{
"girdi": 6,
"kabul": 3,
"tekrar": 1,
"ayrilan": 2,
"ayrilan_kayitlar": [
{
"kayit": 5,
"neden": "Şehir boş veya örnek sözlükte yok"
},
{
"kayit": 7,
"neden": "Şehir boş veya örnek sözlükte yok"
}
]
}
KAYNAK KODU — csv_cleaner.py
"""Small, explicit CSV cleaning example. No network or personal source data."""
import csv
import io
import json
import re
import unicodedata
from pathlib import Path
FIELDS = ["katilimci_kodu", "sehir", "etkinlik"]
CITIES = {"istanbul": "İstanbul", "ankara": "Ankara", "izmir": "İzmir"}
def compact(value):
return " ".join(unicodedata.normalize("NFC", value or "").split())
def city_key(value):
return value.replace("İ", "i").replace("I", "ı").lower()
def clean_csv(source):
reader = csv.DictReader(io.StringIO(source, newline=""), delimiter=";", strict=True)
if reader.fieldnames != FIELDS:
raise ValueError("Beklenen sütunlar: " + ", ".join(FIELDS))
rows, rejected, seen = [], [], set()
duplicates = 0
input_rows = 0
for number, raw in enumerate(reader, start=2):
input_rows += 1
if None in raw or any(raw.get(field) is None for field in FIELDS):
rejected.append({"kayit": number, "neden": "Sütun sayısı uyuşmuyor"})
continue
code, city, event = (compact(raw[field]) for field in FIELDS)
code = code.upper()
if not re.fullmatch(r"U[0-9]{3}", code):
rejected.append({"kayit": number, "neden": "Katılımcı kodu geçersiz"})
continue
canonical_city = CITIES.get(city_key(city))
if canonical_city is None:
rejected.append({"kayit": number, "neden": "Şehir boş veya örnek sözlükte yok"})
continue
if event not in {"giriş", "atölye"}:
rejected.append({"kayit": number, "neden": "Etkinlik türü geçersiz"})
continue
key = (code, event)
if key in seen:
duplicates += 1
continue
seen.add(key)
rows.append(dict(zip(FIELDS, [code, canonical_city, event])))
output = io.StringIO(newline="")
writer = csv.DictWriter(output, fieldnames=FIELDS, delimiter=";", lineterminator="\n")
writer.writeheader()
writer.writerows(rows)
return output.getvalue(), {
"girdi": input_rows, "kabul": len(rows), "tekrar": duplicates,
"ayrilan": len(rejected), "ayrilan_kayitlar": rejected,
}
if __name__ == "__main__":
folder = Path(__file__).parent
cleaned, report = clean_csv((folder / "sample-input.csv").read_text(encoding="utf-8"))
(folder / "cleaned-output.csv").write_text(cleaned, encoding="utf-8", newline="")
(folder / "csv-report.json").write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps(report, ensure_ascii=False))