Bank OCR
Level: Intermediate 30–60 minConcepts: AlgorithmsParsingValidationEdge Cases
You work at a bank that has just purchased a machine to read account numbers from paper documents. The machine scans the documents and produces a file of ASCII art digits.
Step 1: Parse Digits
Each account number is 9 digits long, written using pipes and underscores in a 3x3 grid:
_ _ _ _ _ _ _
| _| _||_||_ |_ ||_||_|
||_ _| | _||_| ||_| _|
The above represents: 123456789
Each digit occupies exactly 3 columns and 3 rows:
_ _ _ _ _ _ _ _
| | | _| _||_||_ |_ ||_||_|
|_| ||_ _| | _||_| ||_| _|
0 1 2 3 4 5 6 7 8 9
Write a function that takes the 3-line string representation and returns the account number as a string (e.g. "123456789").
Step 2: Validate Checksum
Each account number has a checksum. Given account number d1 d2 d3 d4 d5 d6 d7 d8 d9:
checksum = (d1*9 + d2*8 + d3*7 + d4*6 + d5*5 + d6*4 + d7*3 + d8*2 + d9*1) mod 11 == 0
Example: 345882865 → (3*9 + 4*8 + 5*7 + 8*6 + 8*5 + 2*4 + 8*3 + 6*2 + 5*1) = 231 → 231 mod 11 = 0 → valid
Report the status of each account:
- Valid account: just the number (e.g.
345882865) - Invalid checksum: append
ERR(e.g.345882866 ERR) - Illegible digit: append
ILL(e.g.34588286? ILL)
Step 3: Error Correction
For accounts with a single illegible digit (?) or invalid checksum, try correcting by finding the closest valid account number. A “close” account number differs by a single pipe or underscore in the ASCII representation (one segment added or removed).
If exactly one valid alternative exists, use it. If multiple alternatives exist, report them all.
Test Cases
| Input (ASCII) | Parsed | Status |
|---|---|---|
All zeros (9x " _ | ||_|") | 000000000 | Valid |
All ones (9x " | |") | 111111111 | ERR |
123456789 pattern | 123456789 | Valid |
| One garbled digit | 12345678? | ILL |
Hint
Start with parsing a single digit. Get all 10 digits working, then combine into a 9-digit parser. Checksums and error correction are separate concerns — build them as independent layers.