Exercise 1: <= and != Also Need the Lookahead Fix — Possible Solution ==================================================================== THE TEST ------------------------------ for op_text in ("<=", "!="): q = f"SELECT * FROM t WHERE x {op_text} 5;" naive_ops = [t for t in tokenize_naive(q) if t.kind == 'OP'] fixed_ops = [t for t in tokenize(q) if t.kind == 'OP'] RESULT ------------------------------ '<=': naive -> [Token('OP','<'), Token('OP','=')] fixed -> [Token('OP','<=')] '!=': naive -> [Token('OP','!'), Token('OP','=')] fixed -> [Token('OP','!=')] Both operators split into two separate tokens under the naive tokenizer, and both are correctly recognized as ONE token under the fixed tokenizer. WHY THE SAME FIX HANDLES BOTH, WITH NO SPECIAL-CASING ------------------------------ The fixed tokenizer's own operator branch is: if ch in '=<>!': if i + 1 < n and sql[i + 1] == '=': tokens.append(Token('OP', ch + '=')) i += 2 else: tokens.append(Token('OP', ch)) i += 1 The condition `ch in '=<>!'` matches ANY of the four operator-starting characters -- '=', '<', '>', or '!' -- not just '>' specifically. Once inside that branch, the lookahead check (`sql[i+1] == '='`) doesn't care WHICH of the four characters ch happens to be; it only asks "is the very next character an equals sign?" If so, it combines the current character with that next '=' into a single two-character token (ch + '='), covering '==' -- not a real SQL operator here, but harmless -- as well as the three that matter: '<=', '>=', and '!='. This is why testing '<=' and '!=' separately isn't really testing two DIFFERENT fixes -- it's confirming that the ONE fix, written generically in terms of "any operator character followed by =", automatically covers every operator that happens to fit that same pattern, without needing three separate if-branches (one hardcoded for '>=', one for '<=', one for '!='). WHY THIS WORKS AS AN ANSWER ------------------------------ This confirms the fix's own generality was a deliberate design choice worth verifying independently, not an accident that happened to work for the chapter's own single '>=' example. A tokenizer that only fixed '>=' specifically (e.g., a special case checking literally for the two characters '>' then '=') would have left '<=' and '!=' just as broken as before -- testing multiple operators is what distinguishes a genuinely general fix from a narrow, single-case patch.