65 · Valid Number

One Pass, Four Flags

A financial data pipeline rejects malformed entries before parsing — strings like '+3.14', '−1e10', and '0.5E-3' must pass, while 'e', '.', and '1a' must fail. A single left-to-right scan with four boolean flags — tracking whether a digit, dot, exponent, or sign has been seen — validates the structure without backtracking or regex. O(n) time. O(1) space.

- 9 . 5 e 3 digit ●


Classify, check, update, advance

Every character belongs to exactly one category, and its legality depends on what has been seen so far.

character classes

Five possible classes: digit (0–9), sign (+/−), dot (.), exponent (e/E), or invalid. Any character outside these classes immediately rejects the string.

context-sensitive rules

A sign is only legal at position 0 or directly after an exponent. A dot is rejected if one already appeared or if an exponent has started. An exponent requires that at least one digit has been seen.

end-of-scan conditions

Passing every character check is necessary but not sufficient. Two final conditions must hold: at least one digit was seen (hasDigit), and if an exponent appeared, at least one digit followed it (hasDigitAfterExponent).


The scan loop

One pass, four flags, immediate rejection on any illegal character.

  1. Initialize flags

    Set hasDigit = false, hasDot = false, hasExponent = false, hasDigitAfterExponent = true (vacuously true — no exponent yet).

  2. Classify the character

    Map the current character to one of five classes: digit, sign, dot, exponent, or invalid. Invalid characters reject the string immediately.

  3. Check context and update flags

    Each class has rules. Digits always accepted — set hasDigit and possibly hasDigitAfterExponent. Signs require position 0 or post-exponent. Dots require no prior dot and no active exponent. Exponents require a prior digit and no prior exponent.

  4. Final verdict

    After scanning all characters: check hasDigit and hasDigitAfterExponent. Both must be true for the string to be a valid number.


Where the scan traps you

Three categories of tricky inputs that test your flag logic.

Leading or trailing dot

".1" and "4." are both valid. A decimal point does not require digits on both sides — it only requires that at least one digit exists somewhere. Demanding digits on both sides of the dot is the classic mistake.

Exponent without trailing digit

"1e+" is invalid even though every character is individually legal. The sign after the exponent is fine, but hasDigitAfterExponent stays false because no digit follows. The end-of-scan check catches this.

Dot after exponent

"99e2.5" is invalid. Once the exponent portion begins, the mantissa is sealed — no decimal points are allowed in the exponent. The hasExponent flag blocks the dot.