8 điểm bởi GN⁺ 2025-09-22 | 1 bình luận | Chia sẻ qua WhatsApp
  • Sj.h là một trình phân tích cú pháp JSON siêu nhẹ chỉ gồm khoảng 150 dòng, có thể dùng trong môi trường dựa trên C99
  • Có các đặc điểm như không cấp phát bộ nhớ, duy trì trạng thái tối thiểu, nên phù hợp cho môi trường nhúng gọn nhẹ hoặc khi cần giảm tối đa phụ thuộc
  • Áp dụng cách xử lý trực tiếp đối với phân tích số và chuỗi, cho phép người dùng tự do triển khai phần xử lý liên quan
  • Hỗ trợ thông báo lỗi dựa trên dòng:cột, giúp debug dễ đọc hơn và dễ xác định vị trí hơn
  • Là phần mềm thuộc phạm vi công cộng, cho phép mọi người tự do sử dụng, chỉnh sửa và phân phối

Giới thiệu dự án

  • Sj.h là tệp header C99 cung cấp chức năng phân tích JSON chỉ với lượng mã tối thiểu, không có tính năng dư thừa hay cấp phát bộ nhớ không cần thiết
  • Toàn bộ phần triển khai chỉ khoảng 150 dòng, phù hợp cho hệ thống nhúng, công cụ, hoặc các trường hợp muốn giảm phụ thuộc vào thư viện bên ngoài

Tính năng chính

  • Hoạt động với không cấp phát bộ nhớ (zero-allocations)trạng thái tối thiểu (minimal state) nên áp lực bộ nhớ rất thấp
  • Thông báo lỗi có kèm thông tin dòng:cột, giúp dễ xác định vị trí sự cố phát sinh trong quá trình phân tích
  • Không cung cấp sẵn phân tích số; người dùng có thể dùng cách mình muốn như strtod, atoi
  • Phân tích chuỗi cũng có thể tự triển khai, hoặc xây dựng thêm xử lý Unicode surrogate pair tùy nhu cầu
  • Toàn bộ mã nguồn được cung cấp theo public domain (Unlicense), nên có thể dùng và chỉnh sửa mà không bị ràng buộc về giấy phép

Ví dụ sử dụng

  • Cung cấp ví dụ đơn giản về việc phân tích chuỗi JSON thành cấu trúc Rect
    char *json_text = "{ \"x\": 10, \"y\": 20, \"w\": 30, \"h\": 40 }";  
    typedef struct { int x, y, w, h; } Rect;  
    ...  
    
  • Sử dụng các API đơn giản, rõ ràng như sj_Reader, sj_Value, sj_reader, sj_read, sj_iter_object
  • Phân tích giá trị số hay so sánh key-value cần tự triển khai (không có builtin)
  • Có thể xem thêm nhiều ví dụ sử dụng khác trong thư mục demo

Giấy phép

  • Sj.hphần mềm public domain mà ai cũng có thể sử dụng không hạn chế
  • Xem thêm chi tiết trong tệp LICENSE

Khác

  • Mã nguồn và cấu trúc thư mục đơn giản, có thể dùng ngay mà không cần bước cấu hình hay build riêng
  • Độc lập, không có phụ thuộc bên ngoài, phù hợp chủ yếu với các môi trường yêu cầu tính gọn nhẹdễ sử dụng

1 bình luận

 
GN⁺ 2025-09-22
Ý kiến trên Hacker News
  • Lý do tôi thích tác phẩm của tác giả này là phần lớn đều là các thư viện một file viết bằng ANSI C hoặc Lua, tập trung đúng phạm vi, cung cấp giao diện dễ dùng và tài liệu rất tốt, tôi cũng thích cả giấy phép phần mềm miễn phí của chúng; ngoài dự án này ra, còn vài tác phẩm khác của tác giả mà tôi thích: log.c (thư viện logging C99 đơn giản), microui (thư viện UI immediate-mode cực nhỏ), fe (một ngôn ngữ nhỏ có thể nhúng), microtar (thư viện tar gọn nhẹ), cembed (công cụ nhúng file vào C header), ini (thư viện gọn nhẹ cho file cấu hình .ini), json.lua (thư viện JSON gọn nhẹ cho Lua), lite (trình soạn thảo văn bản nhẹ viết bằng Lua), cmixer (audio mixer đa nền tảng cho game), uuid4 (thư viện uuid4 nhỏ viết bằng C)
    • Tôi dùng log.c trong hầu như mọi dự án C, trước giờ không biết tác giả đã làm nhiều thư viện như vậy, log.c thực sự rất dễ dùng nên có thể mạnh dạn đề xuất
    • Hồi làm game với LOVE2D tôi từng dùng thư viện Lume, ngoài đời tôi cũng đã gặp tác giả vài lần trong phòng chat IRC, có lần tôi còn bảo một ý tưởng của tác giả là dở, nhưng nhìn lại thì đó lại là ý hay, đáng để xem https://github.com/rxi/lume
    • Là open source đấy, nhưng không phải free software đúng nghĩa
  • Thư viện này không kiểm tra signed integer overflow ở các dòng sau: L89, L149, L150; với một số đầu vào nhất định có thể xảy ra undefined behavior
    • Một số lập trình viên thích văn hóa thư viện C single-header đơn giản, streamer như Tsoding là ví dụ tiêu biểu, và họ hiểu rằng các thư viện kiểu này không tập trung vào bảo mật hay đầy đủ tính năng; không phải mọi dự án đều là phần mềm cấp doanh nghiệp phơi ra cho vô số khách hàng, nên cách làm này cũng có chỗ đứng
    • Có một bài viết hay nói về sự phình to của các thư viện cố xử lý mọi edge case, cùng thảo luận liên quan; cứ cố xử lý mọi lỗi thì độ phức tạp tăng vọt, và đôi khi việc đó vốn không phải trách nhiệm của thư viện
    • UB chỉ có thể xảy ra nếu độ sâu vượt quá 2 tỷ cấp, hoặc ở trường hợp thứ hai là số dòng vượt quá 2 tỷ; nếu giới hạn đầu vào JS ở 1GB thì khi vượt mức đó nhiều phần khác của stack còn gặp vấn đề lớn hơn, nếu tôi phải xử lý JSON lớn hơn 2GB thì tôi sẽ đổi toàn bộ int trong mã nguồn sang 64-bit, nhưng nếu đầu vào vượt quá 2^64 thì cuối cùng vẫn chết thôi, nên tôi không định đi kiểm tra int overflow ở mọi chỗ trong code
    • int là 32-bit, chỉ khi mỗi dòng có độ lồng hơn 2 tỷ, hoặc file có hơn 2 tỷ dòng, hoặc một dòng dài hơn 2 tỷ ký tự thì mới thành vấn đề
    • Có vẻ tôi sẽ không dùng thư viện này trong production
  • Thư viện này khá dễ dãi, không thể nói cách đó là sai, nhưng người dùng không xem mã nguồn thì cần cẩn thận; đó cũng là lý do chính khiến code nhỏ như vậy; nhìn ví dụ demo trong README thì nó hoạt động như thế này<br><code>{"x",10eee"y"22:5,{[:::,,}]"w"7"h"33<br>rect: { 10, 22, 7, 33 }</code>
    • Parser này nhìn chung giả định đầu vào là hợp lệ; việc validation là một bài toán hoàn toàn khác mà thư viện này không bao phủ, rốt cuộc vai trò của nó là trích xuất dữ liệu
    • Vậy như thế là sai à?
  • Tôi nghĩ thư viện parser JSON nói chung là một hố đen đau khổ, mỗi cái lại nhắm đến nơi áp dụng khác nhau, đầy các tầng trừu tượng phức tạp, nhiều khi còn dính cả hai; thật ra nếu chỉ làm đúng phần cần cho mục đích cụ thể thì đây không phải vấn đề quá khó
    • Thật ngạc nhiên khi thấy thư viện JSON hiện đại có thể trở nên phức tạp đến mức nào; thư viện JSON single-header C++ rất đơn giản ngày xưa của nlohmann giờ đây<br>* đã 13 năm tuổi
  • vẫn merge pull request rất tích cực
  • có 122 triệu unit test

vậy mà chính họ cũng thừa nhận nó không phải nhanh nhất, nếu thực sự cần tốc độ thì họ khuyên dùng simdjson; tốt nhất là đừng tự viết thư viện parser JSON, 90% đầu tiên có thể xong trong 45 phút, nhưng 10% còn lại sẽ ngốn hàng nghìn giờ lao động của cả một vạn người

  • Có một tài liệu nổi tiếng là Parsing JSON is a Minefield (2016) https://seriot.ch/projects/parsing_json.html
  • Có lẽ hiếm có thiết kế nào trung tính như thư viện này: nó chỉ lặp và trả về key cùng item của mảng, rồi phân loại kiểu bằng string-slice
  • Dự án này quảng bá zero-allocation và lưu trạng thái tối thiểu, nhưng với những kiểu dùng thường xuyên nhất như string thì cuối cùng vẫn cần cấp phát; đây là một hướng thay thế rất khác với bài toán của tôi
  • Tôi vẫn mong S-Expressions tiếp tục được yêu mến
  • Khá thú vị, nhưng tôi tò mò không biết thư viện này vượt qua được bao nhiêu bài conformance test https://github.com/nst/JSONTestSuite
    • Về mặt validation thì thư viện này có vẻ không nghiêm ngặt lắm, ví dụ nó chấp nhận đóng object hay array bằng cả ] lẫn }, và còn coi \v là whitespace nên dễ dãi hơn chuẩn; có lẽ nên xem nó là một "bộ trích xuất dữ liệu cho JSON đúng" hơn; tuy nhiên tự viết parser cho string hay number cũng có thể khá phiền, nhất là khi cần thống nhất với bên sinh dữ liệu về một tập con cú pháp JSON nào đó
    • Tôi nghĩ việc tạo bộ conformance test dựa trên triển khai thực tế sẽ rất hữu ích: tạo test-set đúng bằng tập con/tập siêu của hành vi một thư viện parser cụ thể, để tránh rủi ro hai parser diễn giải cùng một JSON theo hai cách khác nhau và tạo ra lỗ hổng, chẳng hạn bypass xác thực
    • Hỏi thật là nó có hỗ trợ object lồng nhau không?
  • Trông hơi giống một parser nửa vời, vì nó không chuyển number sang float hay int, nên có vẻ bạn sẽ phải tự thêm phần đó; dù vậy vẫn rất ấn tượng và tôi sẵn sàng dùng thử, chỉ là muốn chỉ ra điểm đó thôi
  • Tôi thắc mắc không biết C99 có quy định struct này mặc định được khởi tạo bằng 0 hay không, hay là đã thiếu = { 0 }; nhìn đoạn code liên quan thì có vẻ r->depth chưa được khởi tạo mà vẫn có thể tình cờ bằng depth trong vòng lặp sj__discard_until
  • Tôi tò mò mục đích dùng của loại thư viện này là gì, khi đã có khá nhiều thư viện JSON rất tốt rồi; nó là công cụ phục vụ học tập à?
    • Nó dễ tích hợp vào codebase hiện có, ít gánh nặng về kích thước, không dùng heap allocation, cũng không dùng stdlib (chỉ include stdbool.hstddef.h để định nghĩa kiểu), không có trò template C++ rối rắm và API thì trực quan; thư viện C đáp ứng đủ các điều kiện này thực sự rất hiếm, C++ còn hiếm hơn
    • Việc parse mà không có overhead và không cần allocation rất hấp dẫn, hữu ích khi muốn trích xuất chỉ một vài thuộc tính từ các json dump lớn, ví dụ như dump của Wikidata
    • Có thể dùng ngay trên CPU nhúng, thậm chí giờ có vẻ mấy thiết bị như vape cũng chạy được API server rồi
    • Vì code nhỏ nên việc review cũng dễ hơn trong các dự án đòi hỏi bảo mật nghiêm ngặt, và compliance về license cũng cực kỳ đơn giản (không cần câu thông báo bản quyền)
    • Nó có thể là codebase tốt cho người mới tham khảo hoặc cho ai muốn xử lý parsing đơn giản, hữu ích khi cần code footprint nhỏ trong các dự án hobby nhỏ với bộ xử lý hạn chế; dù vậy nếu là trường hợp đó thì có lẽ tôi vẫn thích định dạng như TOML hơn
  • Hay đấy! Lần tới nếu cần parser JSON bằng C tôi sẽ xem thử, nhiều năm nay tôi dùng cJSON rất ổn (https://github.com/DaveGamble/cJSON), trước đó tôi từng dùng wjelement (https://github.com/netmail-open/wjelement), nhưng rồi đã chuyển vì vài vấn đề nào đó (cụ thể thì lâu quá nên tôi không còn nhớ)
  • Gọi đây là parser thì có vẻ hơi miễn cưỡng, nói chung nó gần với lexer hơn