Mundarija (33)
- Bu darsda
- 1. Nega bu kerak?
- 2. CSV'ni o'qish: RFC 4180
- 2.1 Nega split(",") yetmaydi
- 2.2 Holat mashinasi
- 3. Excel bilan do'st CSV
- 3.1 Eksport: uch qoida (takror)
- 3.2 Import: Excel ru/uz sozlamasi
- 4. PapaParse
- 4.1 O'qish: Papa.parse
- 4.2 Xatolar va qator raqami
- 4.3 React'da import: fayldan jadvalgacha
- 4.4 Yozish: Papa.unparse va formula
- 4.5 Katta fayl: bo'laklab o'qish
- 5. Haqiqiy Excel fayli: .xlsx
- 5.1 .xlsx ichida nima bor
- 5.2 SheetJS
- 5.3 ExcelJS: stil bilan yozish
- 5.4 Hajm
- 6. Hujumchi nigohi
- 7. Vazifalar qadami: CSV eksport va import (holat 15)
- 7.1 O'zgarishlar
- 7.2 Import oqimi
- 7.3 Natija
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): bo'sh joylarni to'ldiring
- 2-mashq (o'rta): eksport tugmasi va formula
- 3-mashq (qiyin): ajratgichni aniqlash
- 4-mashq: Vazifalar qadami
- 10. Real ishda
- Xulosa
- Manbalar
Excel va CSV React'da: import, eksport, PapaParse va SheetJS
Qisqacha: CSV — eng oddiy jadval formati, lekin uni to'g'ri o'qish uchun RFC 4180 qoidalari kerak: qo'shtirnoq ichidagi vergul va yangi qator,
""— bitta qo'shtirnoq. Excel uchun eksportda uchta narsa: BOM (aks holda o'zbek va kirill harflari buziladi), CRLF va formula himoyasi ('=). Importda — ajratgichni aniqlash (rus/o'zbek Excel;bilan saqlaydi), har qatorni tekshirish va xatoni qator raqami bilan aytish. PapaParse bularning hammasini qiladi (+6.6 KB gzip); haqiqiy.xlsxuchun SheetJS (+90.3 KB) yoki ExcelJS (+248.6 KB, stillar bilan).vazifalarkanoni o'z 150 qatorlikcsv.tsini yozdi (+0.7 KB).
Bu darsda
- CSV'ni RFC 4180 bo'yicha o'qiydigan holat mashinasini tushunasiz va ajratgichni aniqlaysiz.
- Excel'da to'g'ri ochiladigan CSV eksport qilasiz va Excel'dan kelgan faylni import qilasiz.
- Importni har qator bo'yicha tekshirib, foydalanuvchiga aniq xato aytasiz.
- PapaParse bilan CSV o'qiysiz va yozasiz, katta faylni bo'laklab o'qish yo'lini bilasiz.
.xlsxuchun SheetJS va ExcelJS'ni hajm, imkoniyat va xavfsizlik bo'yicha tanlaysiz.
Oldin bilishingiz kerak: File va Blob (CSV va BOM asoslari), Faylni o'qish va oldindan ko'rish, Fayl yuklash UI, Jadvallar I: TanStack Table asoslari, Compound komponentlar va slot naqshi (CSV injection).
1. Nega bu kerak?
Oldingi darsda PDF yaratdik — u o'qish uchun. Jadval esa ishlash uchun: Jasur akaning buxgalteri oylik sotuvni Excel'da ochib, formulalar bilan hisoblaydi. Teskarisi ham bor: yetkazib beruvchi narxlar ro'yxatini Excel'da yuboradi, uni saytga yuklash kerak.
File va Blob darsida menyuni CSV qilib yuklab olgansiz: ; ajratgich, CRLF, BOM. Compound komponentlar darsida vazifalar statistikasini CSV hisobot qilgansiz va formula injection'dan himoyalagansiz. Bu dars uchta yangi narsa qo'shadi:
- O'qish (import) — yozishdan ancha qiyin: foydalanuvchi fayli har xil bo'ladi.
- Haqiqiy Excel fayli (
.xlsx) — CSV emas, ZIP ichidagi XML. - Katta fayllar — 100 000 qatorni interfeysni muzlatmasdan o'qish.
Hayotiy o'xshatish: pochta. Xat yuborish oson — o'zingiz yozasiz. Xat qabul qilish qiyinroq: konvert yirtiq, manzil chalkash, ichida boshqa narsa bo'lishi mumkin. Qabul qiluvchi har konvertni tekshiradi.
2. CSV'ni o'qish: RFC 4180
2.1 Nega split(",") yetmaydi
Birinchi xayol: qatorlarga split("\n"), kataklarga split(","). Mana Excel saqlagan haqiqiy qator:
1,"Non, ""sut"" olish",yo'qsplit(",") to'rtta bo'lak beradi: 1, "Non, ""sut"" olish", yo'q. Aslida esa uchta katak: 1, Non, "sut" olish, yo'q. CSV qoidalari (RFC 4180 — CSV formatining standart hujjati):
| Qoida | Misol | Ma'nosi |
|---|---|---|
| maxsus belgili katak qo'shtirnoqda | "Non, sut" |
ichidagi vergul — ajratgich emas |
| ichki qo'shtirnoq — ikki marta | "say ""salom""" |
say "salom" |
| qo'shtirnoq ichida yangi qator | "1-qator↵2-qator" |
bitta katak, ikki qatorli |
| qator oxiri — CRLF | \r\n |
LF ham qabul qilinadi |
Uchinchi qoida eng ko'p buzadi: bitta "qator" fayldagi ikki qatorga cho'zilishi mumkin. Demak, avval qatorlarga bo'lib bo'lmaydi — faylni belgi-belgi o'qish kerak.
2.2 Holat mashinasi
vazifalar kanonidagi csvOqi aynan shunday qiladi. Bitta o'zgaruvchi "hozir qo'shtirnoq ichidamizmi?" deb eslaydi — bu holat mashinasi (state machine): har belgining ma'nosi holatga bog'liq. Kanon kodi (BOM bu yerda "\uFEFF" bilan yozilgan — kanonda belgining o'zi):
const BOM = "\uFEFF";
function csvOqi(matn: string): string[][] {
const toza = matn.startsWith(BOM) ? matn.slice(1) : matn;
const birinchiQator = toza.split(/\r?\n/, 1)[0] ?? "";
const ajratgich =
(birinchiQator.match(/;/g)?.length ?? 0) >
(birinchiQator.match(/,/g)?.length ?? 0)
? ";"
: ",";
const qatorlar: string[][] = [];
let qator: string[] = [];
let katak = "";
let qoshtirnoqda = false;
for (let i = 0; i < toza.length; i++) {
const belgi = toza[i];
if (qoshtirnoqda) {
if (belgi === '"' && toza[i + 1] === '"') {
katak += '"';
i++;
} else if (belgi === '"') {
qoshtirnoqda = false;
} else {
katak += belgi;
}
} else if (belgi === '"') {
qoshtirnoqda = true;
} else if (belgi === ajratgich) {
qator.push(katak);
katak = "";
} else if (belgi === "\n" || belgi === "\r") {
if (belgi === "\r" && toza[i + 1] === "\n") {
i++;
}
qator.push(katak);
katak = "";
if (qator.some((k) => k !== "")) {
qatorlar.push(qator);
}
qator = [];
} else {
katak += belgi;
}
}
qator.push(katak);
if (qator.some((k) => k !== "")) {
qatorlar.push(qator);
}
return qatorlar;
}
console.log(csvOqi('1,"Non, ""sut"" olish",yo\'q\r\n'));
console.log(csvOqi('a\n\n"1-qator\n2-qator"\n'));
console.log(csvOqi(`${BOM}matn;bajarildi\r\nNon, sut;ha\r\n`));Konsolda:
[ [ '1', 'Non, "sut" olish', "yo'q" ] ]
[ [ 'a' ], [ '1-qator\n2-qator' ] ]
[ [ 'matn', 'bajarildi' ], [ 'Non, sut', 'ha' ] ]Uch natijani qoidalar bilan solishtiring:
- Birinchi — qo'shtirnoq ichidagi vergul katakda qoldi,
""→". - Ikkinchi — bo'sh qator o'tkazildi (
qator.some((k) => k !== "")), qo'shtirnoq ichidagi\nkatakning bir qismi bo'ldi. Node uni\ndeb ko'rsatadi — aslida bu haqiqiy yangi qator belgisi. - Uchinchi — BOM tashlandi, ajratgich
;aniqlandi: birinchi qatorda;vergullardan ko'p. Shuning uchunNon, sutdagi vergul ajratgich emas.
Ajratgichni aniqlash — taxmin. Birinchi qator matn dan iborat bo'lsa (hech biri yo'q), vergul tanlanadi. Bu kanon uchun yetarli: sarlavha doim kamida ikki ustunli.
Tekshirib ko'ring: Nega
csvOqiavvaltoza.split(/\r?\n/, 1)qiladi, garchi «Negasplit(",")yetmaydi» bo'limida "qatorlarga bo'lib bo'lmaydi" degan bo'lsak ham?
Javob
Faqat birinchi qatorni olish uchun — ajratgichni aniqlashga. split ning ikkinchi argumenti 1 — "faqat birinchi bo'lakni ber". Sarlavha qatori odatda oddiy so'zlar (matn, bajarildi) — unda qo'shtirnoqli yangi qator deyarli bo'lmaydi. Ma'lumotning o'zi esa keyin belgi-belgi o'qiladi.
3. Excel bilan do'st CSV
3.1 Eksport: uch qoida (takror)
Eksport qoidalarini oldingi darslardan bilasiz, bu yerda — qisqa ro'yxat:
- BOM (
\uFEFF) — fayl boshida. Busiz Excel faylni eski kodlashda ochadi va—,«», kirill harflari buziladi. - CRLF — qator oxiri
\r\n. - Formula himoyasi —
=,+,-,@bilan boshlangan katak oldiga'. Aks holda=HYPERLINK(…)formula bo'lib bajariladi (Compound komponentlar darsidagi hujum).
Kanonda bu qoidalar bitta csvKatak + csvYoz juftligida va statistika hisobotidan (18-qism) ham shu yerga ko'chdi. Endi vazifalar va statistika — bitta kod.
3.2 Import: Excel ru/uz sozlamasi
Eng qiziq tuzoq — teskari yo'l. Jasur aka eksport faylini Excel'da ochdi, bitta vazifa qo'shdi va «Saqlash» bosdi. Windows'da til sozlamasi rus yoki o'zbek bo'lsa, Excel:
- ajratgichni
;qiladi (vergul — o'nlik kasr belgisi); - "ha/yo'q" ustunida boshqa so'zlar paydo bo'ladi: xodim o'zi
да/нетyozib qo'yadi, mantiqiy formulali katakni esa Excel o'z tilida saqlaydi (inglizcha Excel'daTRUE/FALSE, ruschadaИСТИНА/ЛОЖЬ); - BOM'ni qoldirishi ham, olib tashlashi ham mumkin.
Kanonning csvdanVazifalar funksiyasi shularning hammasini qabul qiladi. "Ha" deb tushuniladigan qiymatlar ro'yxati (kanon kodi):
const HA = new Set(["ha", "true", "1", "yes", "да", "x", "✓"]);
const YOQ = new Set(["yo'q", "yoq", "false", "0", "no", "нет", ""]);Ro'yxatda yo'q qiymat (balki, shuningdek ИСТИНА) — xato, va xato qator raqami bilan: «2-qatorda «bajarildi» noto'g'ri: «balki».». Foydalanuvchi faylni Excel'da ochib, aynan o'sha qatorni tuzatadi. "Fayl noto'g'ri" degan xabar esa uni yuzlab qatorni ko'zdan kechirishga majbur qiladi.
4. PapaParse
4.1 O'qish: Papa.parse
O'z o'quvchingiz kichik ilovaga yetadi. Ko'p ustunli, turli manbali fayllar uchun — PapaParse: RFC 4180, ajratgichni aniqlash, sarlavha, turlarni o'girish, xatolar ro'yxati va katta fayllar uchun oqim. Natija oynasida PapaParse 5.7.0 ishlaydi:
import Papa from "papaparse";
const csv =
"\uFEFFmatn;bajarildi;soni\r\n" +
"Non, sut;да;2\r\n" +
'"Choy; qand";нет;\r\n' +
"\r\n";
export default function App() {
const r = Papa.parse(csv, {
header: true, // birinchi qator — ustun nomlari
skipEmptyLines: true,
dynamicTyping: true, // "2" → 2, bo'sh → null
});
console.log(r.data);
console.log(r.meta.delimiter, r.meta.fields, r.errors);
return <p>{r.data.length} ta qator</p>;
}Konsolda:
(2) [{matn: 'Non, sut', bajarildi: 'да', soni: 2}, {matn: 'Choy; qand', bajarildi: 'нет', soni: null}]
; (3) ['matn', 'bajarildi', 'soni'] (0) []Ekranda:
2 ta qatorheader: true— har qator obyekt:{matn, bajarildi, soni}. Ustun tartibi o'zgarsa ham kod buzilmaydi.- BOM — o'zi tashlandi: birinchi maydon nomi toza
matn. meta.delimiter—;ni o'zi aniqladi.dynamicTyping—"2"son bo'ldi, bo'sh katak —null. Ehtiyot bo'ling: telefon raqami+998900000000ham songa aylanadi va+yo'qoladi. Matn bo'lishi kerak ustunlar uchundynamicTyping: { soni: true }— faqat tanlangan ustun.
4.2 Xatolar va qator raqami
Buzuq faylda PapaParse to'xtamaydi — o'qiydi va xatolarni ro'yxatga yig'adi:
import Papa from "papaparse";
export default function App() {
const bad = Papa.parse('a,b\n1,2,3\n"x', { header: true });
for (const e of bad.errors) {
console.log(e.row, e.code, e.message);
}
return null;
}Konsolda:
2 MissingQuotes Quoted field unterminated
0 TooManyFields Too many fields: expected 2 fields but parsed 3
1 TooFewFields Too few fields: expected 2 fields but parsed 1Tarjimasi: "qo'shtirnoqli maydon yopilmagan", "maydon ko'p: 2 kutilgan, 3 o'qildi", "maydon kam: 2 kutilgan, 1 o'qildi". Diqqat: e.row — ma'lumot qatorining 0 dan boshlangan indeksi, fayldagi qator emas. Foydalanuvchiga ko'rsatishda row + 2 (sarlavha qatori + 1 dan sanash). MissingQuotes ro'yxatda birinchi chiqdi — Papa xatolarni tartiblamaydi.
4.3 React'da import: fayldan jadvalgacha
Endi hammasini bitta komponentga yig'amiz: fayl → matn (file.text()) → PapaParse → har qatorni tekshirish → ro'yxat va xatolar. Natija oynasida fayl tanlash dialogini avtomatik bosib bo'lmaydi, shuning uchun «Namuna fayl» tugmasi o'sha funksiyaga new File(…) beradi:
import { useState } from "react";
import Papa from "papaparse";
const SAMPLE =
"\uFEFFmatn;bajarildi\r\n" +
"Non, sut;ha\r\n" +
'"Choy; qand";нет\r\n' +
";ha\r\n" +
"Go'sht olish;balki\r\n";
const YES = new Set(["ha", "да", "true", "1"]);
const NO = new Set(["yo'q", "нет", "false", "0", ""]);
function parseTasks(text) {
const { data, errors } = Papa.parse(text, {
header: true,
skipEmptyLines: true,
});
const problems = errors.map((e) => `${e.row + 2}-qator: ${e.code}`);
const tasks = [];
data.forEach((row, i) => {
const line = i + 2;
const title = (row.matn ?? "").trim();
const done = (row.bajarildi ?? "").trim().toLowerCase();
if (title === "") {
problems.push(`${line}-qator: matn bo'sh`);
} else if (!YES.has(done) && !NO.has(done)) {
problems.push(`${line}-qator: «${done}» — ha/yo'q emas`);
} else {
tasks.push({ title, done: YES.has(done) });
}
});
return { tasks, problems };
}
export default function App() {
const [result, setResult] = useState(null);
async function handleFile(file) {
if (!/\.csv$/i.test(file.name)) {
setResult({ tasks: [], problems: ["Faqat .csv fayl"] });
return;
}
setResult(parseTasks(await file.text()));
}
return (
<>
<label htmlFor="csv">CSV fayl</label>{" "}
<input
id="csv"
type="file"
accept=".csv,text/csv"
onChange={(e) => {
const file = e.target.files[0];
if (file) handleFile(file);
}}
/>{" "}
<button
onClick={() => handleFile(new File([SAMPLE], "royxat.csv"))}
>
Namuna fayl
</button>
{result && (
<>
<p role="status">{result.tasks.length} ta vazifa o'qildi</p>
<ul>
{result.tasks.map((t) => (
<li key={t.title}>
{t.done ? "✓" : "○"} {t.title}
</li>
))}
</ul>
<ul aria-label="Xatolar">
{result.problems.map((p) => (
<li key={p}>{p}</li>
))}
</ul>
</>
)}
</>
);
}Ekranda:
CSV fayl Namuna fayl
2 ta vazifa o'qildi
✓ Non, sut
○ Choy; qand
4-qator: matn bo'sh
5-qator: «balki» — ha/yo'q emasTo'rt qatordan ikkitasi qabul qilindi, ikkitasi — aniq sabab va qator raqami bilan. Excel'da 4-qatorni ochsangiz, birinchi katak haqiqatan bo'sh. role="status" — Malikaning ekran o'quvchisi natijani o'zi o'qiydi.
Kanon boshqacha qaror qildi: birinchi xatoda butun import to'xtaydi («hammasi yoki hech narsa»). Sabab: import ro'yxatni almashtiradi, yarim fayl bilan almashtirish ma'lumot yo'qotishi bo'lardi. Bizning namunada esa xatolar ko'rsatilgach, foydalanuvchi "baribir qo'shish" ni tanlashi mumkin — ikkala yo'l ham to'g'ri, faqat ongli tanlang.
4.4 Yozish: Papa.unparse va formula
PapaParse yozadi ham — lekin formula himoyasi sukut bo'yicha o'chiq:
import Papa from "papaparse";
export default function App() {
const rows = [{ matn: "=1+1", izoh: 'say "salom"' }];
console.log(Papa.unparse(rows));
console.log(Papa.unparse(rows, { escapeFormulae: true }));
return null;
}Konsolda:
matn,izoh
=1+1,"say ""salom"""
matn,izoh
"'=1+1","say ""salom"""Birinchi natijada =1+1 Excel'da formula bo'lib bajariladi. escapeFormulae: true — oldiga '. Excel uchun BOM va CRLF ham o'zingizdan: "\uFEFF" + Papa.unparse(rows, { newline: "\r\n", escapeFormulae: true }).
4.5 Katta fayl: bo'laklab o'qish
100 000 qatorli fayl (≈10 MB) Papa.parse(matn) bilan bir necha soniya asosiy thread'ni band qiladi — tugmalar javob bermaydi (Asosiy oqimni bo'shatish). PapaParse'da ikki yo'l bor (kod hujjat bo'yicha, kanonda sinalmagan):
Papa.parse(file, {
header: true,
worker: true, // alohida thread'da
step: (row) => {
// har qator kelishi bilan — butun faylni xotirada ushlamaydi
count += 1;
},
complete: () => console.log(`${count} ta qator`),
});step — har qator alohida keladi, fayl xotiraga butunlay yuklanmaydi (oqim g'oyasi). worker: true — tahlil Web Worker da. Worker rejimini qattiq CSP bilan sinab ko'ring: kutubxona worker'ni qanday yaratishiga qarab worker-src yoki Trusted Types siyosati to'sishi mumkin. Ishonchli muqobil — o'z worker faylingiz va uning ichida Papa.parse (Og'ir ishni UI'dan ajratish).
Tekshirib ko'ring: Telefon raqamlari ustuni bor CSV'ni
dynamicTyping: truebilan o'qidingiz.+998 90 000 00 00(bo'shliqlar bilan) va+998900000000(bo'shliqsiz) qanday bo'ladi?
Javob
Bo'shliqli raqam son emas — satr bo'lib qoladi. Bo'shliqsizi esa son bo'lib, 998900000000 ga aylanadi: + yo'qoldi. Bitta ustunda ikki xil tur — keyingi kod chalkashadi. Shuning uchun telefon, pasport raqami, indeks kabi "raqamga o'xshash matn" ustunlarini songa aylantirmang: dynamicTyping ni faqat haqiqiy sonli ustunlarga bering.
5. Haqiqiy Excel fayli: .xlsx
5.1 .xlsx ichida nima bor
CSV — oddiy matn: bitta varaq, stil yo'q, formula yo'q, tur yo'q. Buxgalter esa qalin sarlavha, ustun eni, bir nechta varaq va sana turini xohlaydi. Bu — .xlsx formati (Office Open XML): ZIP arxiv, ichida har varaq uchun XML fayl, stillar, umumiy satrlar jadvali. Shuning uchun kutubxonalar og'ir: ular ZIP siqish va XML'ni o'zlari yozadi va o'qiydi.
5.2 SheetJS
SheetJS (xlsx paketi) — o'qish uchun eng ko'p ishlatiladigani: .xlsx, .xls, .ods, CSV'ni bir xil API bilan o'qiydi (kod hujjat bo'yicha, natija oynasida yo'q):
import * as XLSX from "xlsx";
// O'qish: fayl → varaqlar → obyektlar massivi
const wb = XLSX.read(await file.arrayBuffer());
const sheet = wb.Sheets[wb.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(sheet); // [{matn, …}, …]
// Yozish: obyektlar → varaq → kitob → fayl
const out = XLSX.utils.book_new();
const tasksSheet = XLSX.utils.json_to_sheet(tasks);
XLSX.utils.book_append_sheet(out, tasksSheet, "Vazifalar");
XLSX.writeFile(out, "vazifalar.xlsx");Muhim halol fakt — versiya. npm'dagi xlsx paketining oxirgi versiyasi — 0.18.5, 2022-yil martdan beri yangilanmagan. SheetJS yangi versiyalarini faqat o'z saytidan (cdn.sheetjs.com) tarqatadi: npm i https://cdn.sheetjs.com/…/xlsx-….tgz. 0.18.5 da ma'lum xavfsizlik zaifliklari bor: prototype pollution (CVE-2023-30533, 0.19.3 da tuzatilgan) va ReDoS (CVE-2024-22363, 0.20.2 da tuzatilgan). Foydalanuvchi yuklagan .xlsx ni o'qisangiz, ular aynan sizga tegadi. Kanon tajribasi npm versiyasini o'lchadi: +90.3 KB gzip, CSP 0, bir qatorli kitob — 15 950 bayt.
5.3 ExcelJS: stil bilan yozish
ExcelJS — chiroyli hisobot yozish uchun: ustun eni, shrift, rang, chegara, raqam formati:
import ExcelJS from "exceljs";
const wb = new ExcelJS.Workbook();
const ws = wb.addWorksheet("Vazifalar");
ws.columns = [
{ header: "Matn", key: "matn", width: 40 },
{ header: "Holat", key: "holat", width: 12 },
];
ws.getRow(1).font = { bold: true };
for (const t of tasks) ws.addRow({ matn: t.matn, holat: t.holat });
const buffer = await wb.xlsx.writeBuffer();
const XLSX_TYPE =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
const blob = new Blob([buffer], { type: XLSX_TYPE });
// keyin — W-55 dagi Blob → <a download>Kanon tajribasida (4.4.0) — +248.6 KB gzip, CSP 0, qalin sarlavhali bir qatorli kitob — 6469 bayt. Paket 2023-yildan yangilanmagan va o'rnatishda bir nechta eskirgan bog'liqlik haqida ogohlantirish chiqardi (kutubxonalar-ornatish.txt: inflight, glob@7, rimraf@2, fstream, uuid@8).
5.4 Hajm
- o'z csv.ts (vazifalar, holat 15)birinchi yuklash farqi0,7 KB
- PapaParse 5.7.0CSP 06,6 KB
- SheetJS (npm 0.18.5)CSP 0; npm versiyasi 202290,3 KB
- ExcelJS 4.4.0CSP 0; stil bilan248,6 KB
Manba: O'lchandi: kanon tajribasi va holat 12 → 15, Vite 8.3.3, gzip -9, Chrome 155, natijalar/tajriba/kutubxonalar-21.txt, tekshiruv-15.txt, 2026-10-17
To'rttasi ham vazifalar CSP'si ostida toza (CSP 0) — ular innerHTML ishlatmaydi va tashqariga bormaydi. Farq — faqat hajm va imkoniyat. Qoida: CSV kifoya qilsa — CSV. .xlsx ni o'qish kerak bo'lsa — SheetJS (cdn versiyasi). Stilli .xlsx yozish kerak bo'lsa — ExcelJS, kech yuklash bilan yoki serverda.
6. Hujumchi nigohi
Import — begona faylni ilovaga kiritish. Hujumchi nima qiladi?
- Ulkan fayl. 2 GB CSV — brauzer xotirasi tugaydi, tab yiqiladi. Himoya: o'qishdan oldin hajmni tekshirish. Kanon
faylniTekshirfunksiyasida 1 MB chegara bor (100 ta vazifa ≈ 10 KB). - Ulkan katak. Bitta katakda 5 MB matn. Kanon
Vazifa.MAKS_UZUNLIKbilan har vazifa matnini tekshiradi va qator raqami bilan rad etadi. - Formula qaytib keladi. Eksportda
'=1+1yozdik. Import qilganda'ni olib tashlamasak, vazifa matni'=1+1bo'lib qoladi; olib tashlasak — keyingi eksportda yana qo'yiladi. Kanon importda'ni faqat'=,'+,'-,'@boshida olib tashlaydi — aylanma (eksport → import) matnni o'zgartirmaydi. - HTML katakda.
<img src=x onerror=alert(1)>— React matnni{t.title}sifatida xavfsiz chiqaradi. FaqatdangerouslySetInnerHTMLga bermang (XSS va DOM xavfsizligi). - Eski kutubxona. Yuqoridagi SheetJS 0.18.5 zaifliklari — maxsus yasalgan
.xlsxbilan ishlaydi.
Va asosiysi: klientdagi tekshiruv — qulaylik. Import natijasi serverga ketadi va server uni baribir qayta tekshiradi.
7. Vazifalar qadami: CSV eksport va import (holat 15)
7.1 O'zgarishlar
git switch -c feat/csvKanon PapaParse'ni o'lchadi (+6.6 KB, CSP 0) va qo'shmadi. csv.ts boshidagi izoh sababini aytadi:
// csv.ts — CSV yozish va o'qish (21/#15). Kutubxonasiz:
// PapaParse 5.7.0 o'lchandi (+6.6 KB gzip, CSP 0 —
// natijalar/tajriba/kutubxonalar-21.txt), lekin bizga RFC 4180
// ning kichik qismi kerak: vergul, qo'shtirnoq, qator ichidagi
// yangi qator. Statistika CSV'si (18-qism) ham shu yerdan.
// Excel uchun: boshida BOM (UTF-8 — o'zbek/kirill harflari
// buzilmaydi), qatorlar CRLF. Sof funksiyalar — node:test
// (tekshiruv/csv.test.js)Fayllar:
| Fayl | Nima |
|---|---|
src/csv.ts (yangi) |
csvKatak, csvYoz, csvOqi, vazifalarCsv, csvdanVazifalar |
App.tsx |
eksportCsv() — faylniYuklabBer(…, "text/csv;charset=utf-8") |
Eksport.tsx |
«CSV (Excel uchun)» tugmasi |
Import.tsx, fayl.ts |
.csv ham qabul qilinadi |
batafsil-statistika.ts |
o'z csvKatak i o'chdi → csvYoz |
Eng qiziq o'zgarish — Import.tsx. CSV uchun alohida import yo'li yozilmadi:
+ // 21/#15: CSV — vazifalarga, keyin o'sha JSON paket yo'li (bitta
+ // tekshiruv va bitta import kodi)
+ if (fayl.name.toLowerCase().endsWith(".csv")) {
+ const natija = csvdanVazifalar(matn);
+ if (!natija.ok) {
+ xatoniKorsat(natija.xato, "fayl");
+ return;
+ }
+ matn = eksportMatni(natija.qiymat);
+ }
importQil(matn, "fayl");CSV vazifalarga aylanadi, vazifalar — oddiy JSON eksport matniga (eksportMatni), keyin o'sha importQil. JSON importdagi hamma tekshiruv, server bilan sinxron (PUT) va e'lon — CSV uchun bepul. Ikkinchi import yo'li — ikkinchi xatolar manbai bo'lardi.
Eksport tugmasi — kanon App.tsx dan:
// 21/#15: CSV — Excel'da ochiladi
// (BOM, CRLF, formula himoyasi — csv.ts)
function eksportCsv() {
const nomi = eksportFaylNomi().replace(/\.json$/, ".csv");
faylniYuklabBer(
vazifalarCsv(asosiy),
nomi,
"text/csv;charset=utf-8",
);
elonQil(`${nomi} yuklab olindi.`);
}elonQil — ekran o'quvchiga e'lon: Malika fayl yuklanganini eshitadi (fayl yuklanishi ekranda hech narsani o'zgartirmaydi).
7.2 Import oqimi
flowchart TB
F["Fayl tanlandi"] --> T{"faylniTekshir: .json/.csv, 0 < hajm ≤ 1 MB"}
T -- yo'q --> X1["Xato + fokus fayl maydonida"]
T -- ha --> M["file.text()"]
M --> C{".csv mi?"}
C -- ha --> O["csvdanVazifalar: BOM, ajratgich, qatorlar"]
O -- xato --> X2["«N-qatorda …» + fokus"]
O -- ok --> J["eksportMatni → JSON"]
C -- yo'q --> I["importQil"]
J --> I
I --> S["Ro'yxat almashdi → server PUT → e'lon"]Diagrammadagi ikki xato yo'li ham bir xil tugaydi: xabar, fayl maydoni aria-invalid, fokus o'sha maydonda.
7.3 Natija
Testlar: tekshiruv/csv.test.js — 9 ta (yozish, o'qish, BOM, ;, aylanma, formula, import xatolari). node:test 224 → 233, Vitest 65. Brauzer tekshiruvi (e2e-21, 41 ta), CSV'ga oidlari:
✅ CSV fayl: nomi, BOM, CRLF, qo'shtirnoq, formula himoyasi, kirill: [true,true,["id,matn,bajarildi","1,\"Non, \"\"sut\"\" olish\",yo'q","2,'=1+1 hisobi,ha","3,Ўзбекча кирилл,yo'q",""]]
✅ e'lon: "vazifalar-2026-10-17.csv yuklab olindi."
✅ CSV import: ro'yxat almashdi, serverga PUT, e'lon: [["Choy; qand","Go'sht olish"],[["Go'sht olish",true],["Choy; qand",false]],"2 ta vazifa import qilindi."]
✅ buzuq CSV: qator raqami bilan xato, fayl maydoni belgilangan, fokus unda: ["2-qatorda «bajarildi» noto'g'ri: «balki».","true","import-fayl"]
✅ CSV: CSP buzilishi yo'q: []Birinchi qatorni o'qing — bu brauzer haqiqatan yuklab olgan faylning qatorlari: qo'shtirnoqli matn, '=1+1, kirill harflari. Uchinchisi — Excel-ru uslubidagi fayl (;, да/нет) importi. Birinchi yuklash JS — 221.5 → 222.2 KB gzip (+0.7). axe — 0.
git add -A
git commitCommit (kanon): feat: CSV eksport/import (Excel uchun: BOM, CRLF, ; ajratgich, formula himoyasi).
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Excel'da о kabi belgilar |
BOM yo'q | fayl boshiga \uFEFF |
| Excel hamma narsani bitta ustunga qo'ydi | ajratgich ,, Excel ; kutadi |
; yoki Excel'da "Ma'lumot → Matndan" |
| qator ikkiga bo'lindi | split("\n") qo'shtirnoqli yangi qatorni bo'ldi |
holat mashinasi yoki PapaParse |
import: 1-ustun nomi \uFEFFmatn |
BOM tashlanmagan | o'qishda BOM'ni olib tashlang |
| xato «0-qatorda» | Papa row — 0 dan, sarlavhasiz |
row + 2 |
+998… → 998… |
dynamicTyping |
faqat sonli ustunlarga |
Excel =… ni bajardi |
formula himoyasi yo'q | ' (yoki escapeFormulae) |
| 50 MB fayl tabni yiqitdi | butun fayl birdan | hajm chegarasi, step, worker |
9. Mashqlar
Mashqlar kurs/mashqlar/21/15-csv-excel/ da. Yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): bo'sh joylarni to'ldiring
- Qo'shtirnoq ichidagi qo'shtirnoq CSV'da marta yoziladi
- Excel CSV'ni UTF-8 deb tanishi uchun fayl boshidagi belgi:
- Rus/o'zbek Windows'dagi Excel saqlagan CSV ajratgichi:
- PapaParse'da birinchi qatorni ustun nomlari qiladigan opsiya:
- npm'dagi
xlsxpaketining oxirgi versiyasi:
Yechim
- ikki —
""→". - BOM —
\uFEFF, UTF-8 da 3 bayt. - ; — vergul o'nlik kasr belgisi bo'lgan tillarda.
- header —
header: true, har qator obyekt bo'ladi. - 0.18.5 — 2022; yangilari faqat cdn.sheetjs.com da.
2-mashq (o'rta): eksport tugmasi va formula
Papa.unparse bilan «Bahor» buyurtmalarini CSV qiling: ustunlar taom, soni, izoh. Ma'lumotda ataylab xavfli izoh bor: =HYPERLINK("https://example.com"). Talablar: formula himoyasi, ; ajratgich, CRLF, boshida BOM. Natijani konsolga JSON.stringify bilan chiqaring — BOM va \r\n ko'rinsin.
Ishora: «Yozish: Papa.unparse va formula» bo'limidagi opsiyalar va delimiter.
Yechim
import Papa from "papaparse";
const orders = [
{ taom: "Osh", soni: 2, izoh: "" },
{
taom: "Manti",
soni: 1,
izoh: '=HYPERLINK("https://example.com")',
},
];
export default function App() {
const csv =
"\uFEFF" +
Papa.unparse(orders, {
delimiter: ";",
newline: "\r\n",
escapeFormulae: true,
});
console.log(csv.charCodeAt(0).toString(16)); // BOM
console.log(JSON.stringify(csv.slice(1)));
return <p>{csv.length} belgi</p>;
}Konsolda:
feff
"taom;soni;izoh\r\nOsh;2;\r\nManti;1;\"'=HYPERLINK(\"\"https://example.com\"\")\""Ekranda:
71 belgiBirinchi qator — BOM belgisining kodi (feff): JSON.stringify uni ko'rsatmaydi, chunki BOM — oddiy, faqat ko'rinmas belgi. Shuning uchun uni alohida tekshirdik. \r\n — CRLF. Xavfli izoh '= bilan boshlandi va qo'shtirnoqqa olindi (ichida qo'shtirnoq bor). Excel uni matn sifatida ko'rsatadi.
3-mashq (qiyin): ajratgichni aniqlash
Kanon ajratgichni birinchi qatordagi ; va , sonidan aniqlaydi. Uni yaxshilang: detectDelimiter(text) — ,, ; va tab (\t) dan birini qaytarsin. Qoida: dastlabki 5 ta qatorning (bo'sh bo'lmaganlarining) har birida shu belgi soni bir xil va noldan katta bo'lsin; bir nechta mos kelsa — birinchi qatorda ko'prog'i. Hech biri mos kelmasa — ,. Qo'shtirnoq ichidagi belgilarni sanamang.
Sinov: "a;b\n1;2\n3;4" → ;; "nomi,narxi\n\"Osh, katta\",35000" → ,; "a\tb\n1\t2" → \t; "matn\nNon" → ,.
Ishora: qo'shtirnoq ichini olib tashlash — line.replace(/"[^"]*"/g, ""); sanash — line.split(d).length - 1; mos kelish — every.
Yechim
const CANDIDATES = [",", ";", "\t"];
function detectDelimiter(text) {
const lines = text
.split(/\r?\n/)
.filter((l) => l.trim() !== "")
.slice(0, 5)
.map((l) => l.replace(/"[^"]*"/g, ""));
const count = (line, d) => line.split(d).length - 1;
const fits = CANDIDATES.filter((d) => {
const n = count(lines[0] ?? "", d);
return n > 0 && lines.every((l) => count(l, d) === n);
});
if (fits.length === 0) return ",";
const first = (d) => count(lines[0], d);
return fits.sort((a, b) => first(b) - first(a))[0];
}
const tests = [
"a;b\n1;2\n3;4",
'nomi,narxi\n"Osh, katta",35000',
"a\tb\n1\t2",
"matn\nNon",
];
for (const text of tests) {
console.log(JSON.stringify(detectDelimiter(text)));
}Konsolda:
";"
","
"\t"
","Ikkinchi sinov — tuzoq: qo'shtirnoqni olib tashlamasak, 2-qatorda ikkita vergul bo'lardi (1-qatorda bitta) va , mos kelmasdi. .slice(0, 5) — 100 000 qatorli faylda ham tez: faqat boshi tekshiriladi. PapaParse ham shunga o'xshash: bir nechta qatorni sinab, eng barqaror ajratgichni tanlaydi.
4-mashq: Vazifalar qadami
feat/csv branch'ida «Vazifalar qadami» dagi o'zgarishlarni qiling: src/csv.ts (beshta funksiya), csv.test.js (9 test), App.tsx dagi eksportCsv, Eksport.tsx tugmasi, Import.tsx va fayl.ts dagi .csv, statistika hisobotining csvYoz ga o'tishi.
Yechim
Tekshiruv ro'yxati:
npm test— node 233, Vitest 65;npm run tip,lint,knip— toza (knipstatistikadagi eskicsvKatakqolsa, ishlatilmagan deb aytadi).- «CSV (Excel uchun)» → fayl
vazifalar-YYYY-MM-DD.csv. Excel'da oching: o'zbekcha harflar to'g'ri,=bilan boshlangan vazifa matn bo'lib turibdi. - Excel'da bitta qator qo'shib saqlang (ru/uz sozlamasida
;bilan) va import qiling — ro'yxat almashadi, e'lon «N ta vazifa import qilindi.». - Ataylab
bajarildiustunigabalkiyozing — «2-qatorda «bajarildi» noto'g'ri: «balki».», fokus fayl maydonida. npm run build— birinchi yuklash ~222.2 KB.
10. Real ishda
- Admin panellar — "Excel'ga eksport" va "Excel'dan import" deyarli har CRM, buxgalteriya va do'kon panelida bor. O'zbekistonda fayllar ko'pincha
;va kirill harflari bilan keladi — BOM va ajratgich tuzog'i kundalik masala. - Katta hisobotlar — serverda, oqim bilan (Excel va CSV: eksport va import); brauzer faqat havolani oladi.
- Kod ko'rigida so'raladi: "importda qator raqami bormi?", "formula himoyasi bormi?", "fayl hajmi chegaralanganmi?".
- Intervyu savollari: "CSV'ni nega
splitbilan o'qib bo'lmaydi?", "Excel'da o'zbek harflari nega buziladi?", "100 000 qatorli faylni qanday o'qiysiz?", "CSV injection nima?".
Xulosa
- CSV — RFC 4180: qo'shtirnoqli katakda vergul va yangi qator,
""— qo'shtirnoq; o'qish — holat mashinasi. - Excel uchun eksport: BOM, CRLF, formula himoyasi; import: BOM'ni tashlash,
;ni aniqlash,да/нетkabi qiymatlar. - Import xatosi — qator raqami bilan; PapaParse
row0 dan, sarlavhasiz. - PapaParse (+6.6 KB):
header,dynamicTyping(ehtiyot bilan),escapeFormulae,step/worker. .xlsx= ZIP + XML: SheetJS (+90.3, npm 0.18.5 eskirgan va zaif) va ExcelJS (+248.6, stil).- Kanon: o'z
csv.ts(+0.7 KB), CSV → JSON paket → o'sha import yo'li.
Keyingi dars: QR kod va shtrix-kod — vazifa havolasini QR kod qilish (qrcode.react, kech yuklash), kamera bilan skanerlash va BarcodeDetector.
Manbalar
- RFC 4180: Common Format and MIME Type for CSV Files — rfc-editor.org/rfc/rfc4180
- PapaParse 5.7: "Config" (
header,dynamicTyping,step,worker,escapeFormulae), "Errors" — papaparse.com/docs - SheetJS: "Installation" (cdn.sheetjs.com), "Utility Functions" — docs.sheetjs.com; CVE-2023-30533, CVE-2024-22363
- ExcelJS — github.com/exceljs/exceljs
- OWASP: CSV Injection — owasp.org/www-community/attacks/CSV_Injection
- Kanon:
vazifalarholat 15,natijalar/tekshiruv-15.txt,brauzer-tekshiruv/natija-21-15.txt,natijalar/tajriba/kutubxonalar-21.txt,kutubxonalar-ornatish.txt(2026-10-17)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!