<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Cà Phê &amp; Code — Lập trình</title>
    <link>https://coffeecode.vn/categories/lap-trinh</link>
    <description>Cà Phê &amp; Code là blog dành cho những người yêu công nghệ và lập trình. Nơi chia sẻ kiến thức coding, công cụ hữu ích, xu hướng công nghệ, kinh nghiệm phát triển phần mềm và những câu chuyện phía sau màn hình — tất cả được kể theo cách gần gũi, dễ hiểu, như một cuộc trò chuyện bên tách cà phê.</description>
    <language>vi</language>
    <atom:link href="https://coffeecode.vn/categories/lap-trinh/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Regex thật ra là một cỗ máy trạng thái: engine khớp chuỗi thế nào</title>
      <link>https://coffeecode.vn/posts/regex-01-may-trang-thai</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-01-may-trang-thai</guid>
      <description>Nhiều người dùng regex như phép thuật mà không biết bên trong nó là gì. Thực ra engine làm hai việc: biên dịch mẫu thành một máy trạng thái, rồi chạy máy đó trên input. Bài này mở máy ra xem: python re.DEBUG in opcode thật của mẫu a(b|c)*d, và Go regexp (RE2) chứng minh nó duyệt input tuyến tính — input tăng gấp 5 thì thời gian cũng tăng gấp 5, ns mỗi ký tự gần như hằng số.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Tham lam vs lười trong regex: vì sao .* nuốt cả chuỗi còn .*? thì không</title>
      <link>https://coffeecode.vn/posts/regex-02-greedy-lazy</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-02-greedy-lazy</guid>
      <description>Cùng một mẫu, chỉ thêm một dấu ?, mà kết quả khác hẳn — và tốc độ cũng vậy. Bài này đo thật bằng python re: greedy .* nuốt cả &apos;&lt;b&gt;xin&lt;/b&gt; và &lt;i&gt;bạn&lt;/i&gt;&apos; thành một match, lazy .*? tách đúng bốn thẻ; và trên input 200k ký tự, greedy chậm hơn lazy 785 lần vì phải nhả dần (backtrack). Hiểu cơ chế để chọn đúng và tránh lỗi trích sai.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Neo và ranh giới trong regex: khớp thứ không phải là ký tự nào</title>
      <link>https://coffeecode.vn/posts/regex-03-neo-ranh-gioi</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-03-neo-ranh-gioi</guid>
      <description>^ $ \b \B không khớp ký tự nào, nhưng chúng quyết định mẫu của bạn đúng hay sai chỗ. Bài này đo thật: &apos;cat&apos; khớp 4 chỗ (kể cả trong scatter, category), thêm \b thì chỉ còn 2 từ độc lập; và ^ $ đổi hẳn nghĩa khi bật cờ MULTILINE — từ &apos;đầu/cuối cả chuỗi&apos; thành &apos;đầu/cuối mỗi dòng&apos;. Hiểu anchor zero-width để tìm-thay-thế không dính nhầm.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Lớp ký tự và quantifier: hai viên gạch nền, và cái bẫy \w không phải [a-zA-Z]</title>
      <link>https://coffeecode.vn/posts/regex-04-lop-ky-tu-quantifier</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-04-lop-ky-tu-quantifier</guid>
      <description>Lớp ký tự [...] và quantifier {m,n} là nền của mọi regex, nhưng chúng giấu vài cái bẫy. Bài này đo thật: trên &apos;Hoà&apos;, \w khớp cả chữ à (Unicode) còn [a-zA-Z] thì đứt ở à thành &apos;Ho&apos;; và trên &apos;1234567&apos;, {2,4} greedy lấy 4 trước rồi 3, còn {2,4}? lazy lấy 2 mỗi lần. Xem cả opcode MAX_REPEAT + IN RANGE mà engine biên dịch ra.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Backreference: viên gạch khiến regex &quot;không còn regular&quot; và buộc phải backtracking</title>
      <link>https://coffeecode.vn/posts/regex-05-backreference</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-05-backreference</guid>
      <description>Chỉ một ký hiệu \1 mà đổi cả bản chất lý thuyết của regex. Bài này đo thật: python dùng (\w+)\s+\1 bắt đúng từ lặp &apos;the the&apos;, &lt;(\w+)&gt;...&lt;/\1&gt; khớp thẻ đóng đúng thẻ mở; nhưng Go RE2 từ chối biên dịch \1 với lỗi &apos;invalid escape sequence&apos;. Vì sao khả năng &apos;nhớ cái đã khớp&apos; vượt khỏi máy trạng thái hữu hạn, buộc engine phải backtracking — và vì sao RE2 cố tình không hỗ trợ.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>ReDoS: vì sao một regex 6 ký tự có thể treo cả server của bạn</title>
      <link>https://coffeecode.vn/posts/regex-06-redos-catastrophic</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-06-redos-catastrophic</guid>
      <description>Mẫu (a+)+$ trông vô hại, nhưng gặp đúng input độc nó chạy chậm theo cấp số nhân. Bài này đo thật: với chuỗi &apos;aaaa...!&apos;, python re mất 9 giây chỉ với 28 ký tự, và thời gian gấp đôi mỗi khi thêm một &apos;a&apos; — n=40 sẽ mất hàng ngàn năm. Cùng mẫu đó trên Go RE2 chỉ mất 3 micro-giây, kể cả với 100.000 ký tự. Đây là ReDoS, và cách phòng nó.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>RE2 và Go regexp: cỗ máy đánh đổi tính năng để không bao giờ nổ</title>
      <link>https://coffeecode.vn/posts/regex-07-re2-go-regexp</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-07-re2-go-regexp</guid>
      <description>RE2 (Go, Rust, Google) chạy tuyến tính bằng cách mô phỏng mọi trạng thái cùng lúc thay vì thử-và-quay-lui. Bài này đo thật: cùng mẫu độc (a+)+b, RE2 xử lý 20 triệu ký tự trong 443ms với ns/ký tự hằng số ~22 — trong khi python treo ở 28 ký tự. Cái giá: RE2 từ chối lookahead, lookbehind và backreference, mỗi cái báo một lỗi khác nhau. Khi nào nên chọn nó.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Lookahead và lookbehind: nhìn quanh mà không nuốt, và cái giá của nó</title>
      <link>https://coffeecode.vn/posts/regex-08-lookahead-lookbehind</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-08-lookahead-lookbehind</guid>
      <description>Lookaround cho regex khả năng khẳng định điều kiện về ngữ cảnh mà không tiêu thụ ký tự. Bài này đo thật bằng python: chèn dấu phẩy nghìn &apos;1234567&apos; thành &apos;1,234,567&apos; bằng (?&lt;=\d)(?=(\d{3})+$), kiểm mật khẩu mạnh bằng ba lookahead cùng vị trí, lấy số sau $ bằng (?&lt;=\$)\d+, và bỏ &apos;cats&apos; bằng cat(?!s). Vì sao những phép này mạnh — và vì sao RE2 từ chối chúng.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Unicode trong regex: vì sao \w cắt cụt chữ tiếng Việt và &apos;à&apos; đôi khi không khớp</title>
      <link>https://coffeecode.vn/posts/regex-09-unicode</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-09-unicode</guid>
      <description>Regex và tiếng Việt là mỏ bug ít người lường trước. Bài này đo thật: python \w bắt &apos;chào&apos; nguyên vẹn nhưng [a-zA-Z] cắt thành &apos;ch&apos;,&apos;o&apos;; Go \w lại chỉ ASCII nên phải dùng \p{L}. Chữ &apos;à&apos; có hai cách mã hóa (NFC 1 codepoint, NFD 2 codepoint) trông giống hệt mà regex khớp khác nhau. Và . khớp 1 rune chứ không phải 1 byte. Cách xử lý cho đúng.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Nhóm bắt và thay thế: dùng regex để biến đổi chuỗi, không chỉ để tìm</title>
      <link>https://coffeecode.vn/posts/regex-10-nhom-bat-thay-the</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-10-nhom-bat-thay-the</guid>
      <description>Regex không chỉ tìm — nó trích và dựng lại. Bài này đo thật: nhóm (...) cắt &apos;2026-09-22&apos; thành ba phần, nhóm đặt tên (?P&lt;nam&gt;) đọc bằng tên, re.sub đổi &apos;yyyy-mm-dd&apos; thành &apos;dd/mm/yyyy&apos; bằng \3/\2/\1, sed đổi &apos;Nguyen Van A&apos; thành &apos;Van A, Nguyen&apos;. Và vì sao (?:...) không được đếm lại quan trọng: thêm một cặp () thừa làm \1 trong thay thế trỏ sai.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Tối ưu regex: bốn mẹo đo được, và một mẹo biến 2 giây thành 0.33 micro-giây</title>
      <link>https://coffeecode.vn/posts/regex-11-toi-uu</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-11-toi-uu</guid>
      <description>Regex chậm hiếm khi vì máy yếu — thường vì mẫu viết chưa khéo. Bài này đo thật bốn kỹ thuật: biên dịch một lần (nhanh 1.84x), lớp phủ định thay lazy (chênh nhỏ nhưng an toàn hơn), atomic/possessive chặn backtracking (2222ms xuống 0.33µs), và neo để loại sớm (68ms xuống 0.21µs, nhanh hơn 329 nghìn lần). Kèm nguyên tắc quan trọng nhất: đo trước khi tối ưu.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Regex thực chiến: phân tích log bằng grep -P, ripgrep và awk — và khi nào nên dừng</title>
      <link>https://coffeecode.vn/posts/regex-12-thuc-chien</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/regex-12-thuc-chien</guid>
      <description>Regex sáng nhất khi mổ log. Bài này đo thật trên 500 dòng access.log: grep -oP trích IP và status code, pipe qua sort|uniq -c xếp hạng (200 chiếm 359, 404 chiếm 75), ripgrep lọc request chậm và POST lỗi, awk tính latency trung bình 405ms. Và ripgrep quét 40MB nhanh gấp đôi grep. Kèm nguyên tắc quan trọng nhất và tổng kết cả loạt 12 phần.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Entropy và giới hạn nén: vì sao dữ liệu ngẫu nhiên không thể nén được</title>
      <link>https://coffeecode.vn/posts/nen-01-entropy</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-01-entropy</guid>
      <description>Mọi thuật toán nén đều đụng một bức tường toán học: entropy Shannon. Bài này đo thật: chuỗi lặp một ký tự (entropy 0) gzip vụt còn 123 byte từ 90.000; nhưng 90.000 byte ngẫu nhiên (entropy 7.998 bit/byte) gzip làm nó phình lên 90.048 byte — không nén nổi. Và vì sao gzip nén text xuống dưới cả giới hạn entropy order-0: nó khai thác thêm sự lặp lại.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Run-length encoding: thuật toán nén đơn giản nhất, thắng đậm và thua thảm</title>
      <link>https://coffeecode.vn/posts/nen-02-rle</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-02-rle</guid>
      <description>RLE thay một dãy ký tự lặp bằng cặp (số lần, ký tự) — đơn giản đến mức viết trong vài dòng. Bài này tự cài RLE và đo thật: nó nén chuỗi lặp 90.000 byte còn 708 byte (127x), bitmap còn 93.5x, nhưng làm text tiếng Anh PHÌNH gấp đôi (93.800 thành 184.800 byte). Vì sao — và vì sao RLE vẫn là viên gạch nền của JPEG và nhiều thuật toán hiện đại.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Huffman coding: gán mã ngắn cho ký tự phổ biến, tiến sát giới hạn entropy</title>
      <link>https://coffeecode.vn/posts/nen-03-huffman</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-03-huffman</guid>
      <description>Vì sao dùng 8 bit cho mọi ký tự khi &apos;e&apos; xuất hiện nhiều hơn &apos;z&apos; hàng trăm lần? Huffman gán mã ngắn cho ký tự phổ biến, mã dài cho ký tự hiếm. Bài này tự cài Huffman bằng heap và đo thật: ký tự phổ biến nhất (khoảng trắng) được mã 2 bit, ký tự hiếm 7 bit; và tổng thể đạt 4.3507 bit/byte — chỉ hơn sàn entropy order-0 (4.3244) đúng 0.026 bit. Vì sao nó không chạm đúng entropy, và arithmetic coding làm gì tốt hơn.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>LZ77 và cửa sổ trượt: nén bằng cách trỏ về đoạn đã thấy, không viết lại</title>
      <link>https://coffeecode.vn/posts/nen-04-lz77</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-04-lz77</guid>
      <description>Huffman khai thác tần suất nhưng mù với lặp lại. LZ77 lo phần đó: gặp đoạn đã xuất hiện, nó thay bằng tham chiếu ngược (lùi N byte, chép M byte). Bài này tự cài LZ77 và đo thật: trên một đoạn văn lặp câu, một token thay được nguyên 51 byte (distance=49, length=51), 9 tham chiếu nuốt 119/184 byte. Đây là chữ L và Z của gzip, zstd và gần như mọi thuật toán nén hiện đại.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>DEFLATE, gzip và zlib: mổ xẻ thuật toán nén phổ biến nhất thế giới</title>
      <link>https://coffeecode.vn/posts/nen-05-deflate-gzip</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-05-deflate-gzip</guid>
      <description>gzip có mặt ở khắp nơi — HTTP, PNG, file .gz — và bên trong nó là DEFLATE: đúng hai thứ ta vừa học, LZ77 chồng lên Huffman. Bài này mổ header gzip thật byte-by-byte (magic 1f 8b, method 08, CRC32, kích thước gốc), so ba lớp vỏ DEFLATE raw / zlib / gzip khác nhau đúng 6 và 18 byte, và chứng minh sức mạnh nằm ở DEFLATE chứ không phải lớp vỏ: gzip level 0 làm dữ liệu to hơn, level 6 nén 153 lần.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>Mức nén gzip -1 tới -9: vì sao mặc định -9 thường là lãng phí</title>
      <link>https://coffeecode.vn/posts/nen-06-muc-nen</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-06-muc-nen</guid>
      <description>Ai cũng từng gõ gzip -9 nghĩ &apos;nén tối đa&apos;. Nhưng bài này đo thật trên 11MB log: từ gzip -6 lên -9 chỉ nhỏ hơn 7% mà chậm gấp 3.5 lần; zstd còn kịch tính hơn — từ -9 lên -19 nhỏ hơn 17% nhưng chậm gấp 36 lần. Đây là luật lợi ích giảm dần, và cách chọn mức nén theo cách dùng thay vì mặc định lấy mức cao nhất.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>gzip vs bzip2 vs xz vs zstd: bốn thuật toán nén, đo thật để biết chọn cái nào</title>
      <link>https://coffeecode.vn/posts/nen-07-gzip-bzip2-xz-zstd</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-07-gzip-bzip2-xz-zstd</guid>
      <description>Bốn công cụ nén phổ biến, bốn triết lý khác nhau. Bài này nén cùng một file log 25MB bằng cả bốn và đo đủ bốn số: kích thước, tỉ lệ, thời gian nén, thời gian giải nén. Kết quả thật có bất ngờ: zstd -3 nén trong 61ms còn xz mất 7 giây; zstd giải nén 12ms bất kể mức nén; và bzip2 nén chặt nhất trên log này (13.3x) vì BWT hợp dữ liệu lặp. Khi nào chọn cái nào.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
    <item>
      <title>zstd và từ điển: nén nghìn bản ghi JSON nhỏ từ 1.3x lên 4.4x</title>
      <link>https://coffeecode.vn/posts/nen-08-zstd-tu-dien</link>
      <guid isPermaLink="true">https://coffeecode.vn/posts/nen-08-zstd-tu-dien</guid>
      <description>Nén từng bản ghi nhỏ riêng lẻ (cache entry, message, log record ~200 byte) cho tỉ lệ tệ hại vì mỗi lần nén bắt đầu từ số 0. Bài này đo thật trên 3000 JSON nhỏ: nén riêng không từ điển chỉ được 1.3x, nhưng huấn luyện một từ điển 8KB bằng zstd --train rồi nén với nó đạt 4.4x — cải thiện 3.5 lần. Vì sao, và khi nào từ điển là công cụ đúng.</description>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0700</pubDate>
      <category>Lập trình</category>
    </item>
  </channel>
</rss>
