دو قالب دادهای که هر روز با آنها سروکار دارید
CSV زبان مشترک اکسل، نرمافزارهای حسابداری و خروجی سامانههاست. JSON زبان مشترک وب، API ها و فایلهای تنظیمات. پایتون برای هر دو ماژول استاندارد دارد و هر دو یک دام فارسی مهم دارند.
نوشتن CSV که اکسل فارسی را درست نشان دهد
اگر یک CSV با UTF-8 معمولی بسازید و در اکسل ویندوز دوبار کلیک کنید، بهجای «مریم کاشانی» حروف درهم (دم...) میبینید. دلیل: اکسل بدون نشانهی خاص، فایل را با کدگذاری پیشفرض ویندوز میخواند. آن نشانه، BOM است؛ سه بایت در ابتدای فایل که کدگذاری utf-8-sig خودکار میگذارد:
import csv
from pathlib import Path
rows = [
{"code": "KSH-101", "customer": "مریم کاشانی", "area": 6, "price": 57_000_000},
{"code": "TBZ-220", "customer": "رضا احمدی", "area": 12, "price": 98_000_000},
]
path = Path("orders.csv")
with open(path, "w", encoding="utf-8-sig", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["code", "customer", "area", "price"])
writer.writeheader()
writer.writerows(rows)
و newline="": ماژول csv خودش پایان خط را مدیریت میکند؛ بدون این آرگومان، در ویندوز بین هر دو سطر یک سطر خالی ظاهر میشود.
خواندن CSV
with open("orders.csv", encoding="utf-8-sig", newline="") as f:
for row in csv.DictReader(f):
price = int(row["price"]) # همهچیز رشته است!
print(row["customer"], f"{price // 10:,} تومان")
خواندن با utf-8-sig هم امن است: اگر BOM باشد حذفش میکند و اگر نباشد، مثل utf-8 معمولی رفتار میکند. بدون آن، اولین کلید دیکشنری بهجای "code" چیزی مثل "\ufeffcode" میشود و row["code"] خطای KeyError میدهد؛ باگی که ساعتها وقت میگیرد.
JSON
import json
text = json.dumps(rows, ensure_ascii=False, indent=2)
Path("orders.json").write_text(text, encoding="utf-8")
loaded = json.loads(Path("orders.json").read_text(encoding="utf-8"))
print(loaded[0]["customer"]) # مریم کاشانی
with open("orders.json", "w", encoding="utf-8") as f:
json.dump(rows, f, ensure_ascii=False, indent=2) # مستقیم در فایل
بهطور پیشفرض json هر کاراکتر غیرانگلیسی را به شکل \u0645\u0631... مینویسد؛ فایل درست است ولی برای انسان خواندنی نیست و حجمش چند برابر میشود. ensure_ascii=False فارسی را همانطور که هست ذخیره میکند.
| پایتون | JSON | نکته |
|---|---|---|
| dict | object | کلیدها همیشه رشته میشوند |
| list، tuple | array | tuple پس از بارگذاری list میشود |
| None / True | null / true | — |
| Decimal، datetime، set | پشتیبانی نمیشود | TypeError؛ با default=str حل میشود |
نکتههایی که کمتر کسی میداند
- کلید عددی بعد از رفتوبرگشت JSON رشته میشود:
{1: "a"}پس از dumps و loads میشود{'1': 'a'}وd[1]دیگر کار نمیکند. - CSV با جداکنندهی نقطهویرگول (رایج در خروجی اکسل با تنظیمات اروپایی) را با
csv.DictReader(f, delimiter=";")بخوانید؛csv.Snifferهم میتواند جداکننده را حدس بزند. - در قالب CSV اکسل، کد سفارشی مثل
0087صفرهای ابتداییاش را از دست میدهد؛ این کار اکسل است، نه پایتون. فایل را با Data ← From Text/CSV باز کنید و نوع ستون را Text بگذارید. json.dumps(data, ensure_ascii=False, sort_keys=True)خروجی ثابت و قابل مقایسه در git تولید میکند.- برای فایلهای واقعی xlsx (نه CSV) کتابخانهی
openpyxlرا نصب کنید؛ CSV فقط متن است و فرمول، رنگ و چند شیت ندارد.