Reading — step 1 of 5
Read
Serialization (json.dumps)
Parsing has an inverse: take an in-memory value, produce JSON text. The shape is the same recursive dispatch, run in reverse:
serialize(v):
None -> "null" True -> "true" False -> "false"
number -> str(v) # but reject nan/inf!
string -> quote(v) # escaping: the hard part
list -> "[" + ",".join(serialize(x) for x in v) + "]"
dict -> "{" + ",".join(quote(k) + ":" + serialize(v[k]) for k in sorted(v)) + "}"
anything else -> error: not serializable
Escaping: the part everyone half-does
The encoder owns the string rules from the escape lesson, in reverse. Must-escape: ", \, and every control character U+0000–U+001F. The idiom is a single pass over characters — it cannot get the ordering wrong:
The trap is chained str.replace. If you write s.replace('"', '\\"').replace("\\", "\\\\") the second replace re-escapes the backslashes the first one just inserted, turning say "hi" into say \\"hi\\". Doing backslash first fixes that ordering, but the per-character loop makes the whole bug class impossible — prefer it.
Non-ASCII is a choice: é may be emitted raw (UTF-8) or as \u00e9; both are valid JSON. Python's ensure_ascii=True default escapes everything non-ASCII — safe for legacy transports, bloated for everyone else.
Numbers: two sharp edges
nan/infare unrepresentable. The grammar has no token for them. Python'sjson.dumps(float("nan"))emits bareNaNby default — output no strict parser will read back. Passallow_nan=False(or raise, as your serializer should) to fail loudly at write time instead of mysteriously at read time.- Emit what the float is, not what looks nice.
repr(0.1 + 0.2)is0.30000000000000004; emitting a prettier0.3writes a different number. Round-tripping demands the exact shortest-repr text.
Determinism
{"a":1,"b":2} and {"b":2,"a":1} are the same value but different bytes. Sorting keys (Python: sort_keys=True) makes output a pure function of the value — which is what diffing, caching, hashing, and test snapshots all need. This exercise sorts keys for exactly that reason.
Your exercise
Implement serialize (the input-DSL plumbing is provided). The grader-caught mistakes are all in quote: s:with"quote must print "with\"quote", input with a real tab must print "tab\there", and s:back\slash must print "back\\slash" — one escaped quote, one \t, one doubled backslash; if any of those comes out double-escaped, you have the replace-ordering bug above. Keys sort alphabetically: o:name=alice,age=30 must print {"age":"30","name":"alice"} — and note "30" stays a quoted string, because this DSL makes all object values strings. Compact separators throughout: no spaces after , or :.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…