Use only in-memory state. Document identifiers are nonempty strings; text and query arguments are arbitrary strings. Limits are integers excluding booleans. Tokenization is exactly re.findall(r"[a-z0-9]+", text.lower()), using Python's standard re module. Empty or punctuation-only documents are valid.

Prototype: implement tokenize(text) -> list[str] using that rule. Preserve order and duplicate tokens, and return a new list on every call.

Final: implement SearchEngine():

  • add(doc_id, text) -> bool: return False without mutation if that identifier already exists; otherwise store it and return True.
  • get(doc_id) -> str | None: return the exact original text, or None if missing.
  • update(doc_id, text) -> bool: replace an existing document and all of its indexed content; return False without mutation if missing.
  • delete(doc_id) -> bool: remove the document and its indexed content; return False if missing. A deleted identifier may be added again.
  • search(term, limit=10) -> list[tuple[str, int]]: tokenize the query and require exactly one token, otherwise raise ValueError. Return each matching document once, scored by that token's occurrence count.
  • search_phrase(phrase, limit=10) -> list[tuple[str, int]]: tokenize the query and match consecutive tokens. Score by number of starting positions, including overlaps. An empty token sequence returns []. A one-token phrase behaves like term search.
  • Both search methods rank by score descending, then document identifier lexicographically ascending, and return at most limit results. Zero yields []; negative limits raise ValueError. Term-query validation still applies with limit zero. Lists are fresh snapshots.
  • stats() -> tuple[int, int]: return (document_count, total_token_count) across current documents, including empty documents in the document count. Updates and deletions must keep these values correct.

No stale matches may survive updates, deletion, or identifier reuse. Raised errors preserve state, and separate instances are independent. Run python main.py --stage prototype, then python main.py --stage final (the default). Edit exercise.py; leave main.py unchanged.

Drag or use the arrow keys to resize. Home collapses the question; End collapses the editor. Enter or double-click resets the split.
Loading editor…
No results yet.

Complete the starter code, then run the checks.
Results and errors will appear here.