Validating Numeric Strings with Decimal and Scientific Notation
A valid numeric representation consists of a mantissa followed by an optional exponent. The mantissa may be an integer or a decimal value, while the exponent is denoted by 'e' or 'E' followed by a signed integer.
Grammar Spceification
Mantissa formats include:
- Optional sign (
+or-) - Integer component: sequence of digits
- Decimal variations:
- Digits followed by a dot (e.g.,
123.) - Digits, dot, then digits (e.g.,
123.45) - Dot followed by digits (e.g.,
.45)
- Digits followed by a dot (e.g.,
Exponent format:
- Letter
eorE - Optional sign
- At least one digit
Valid instances: "2", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7"
Invalid instances: "abc", "1e", "e3", "99e2.5", "--6"
Flag-Based Linear Scan
Maintain state through boolean indicators during traversal:
class NumberValidator {
public:
bool isValid(string str) {
bool hasDigits = false;
bool hasDot = false;
bool hasExp = false;
bool expHasDigits = true;
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str[i];
if (isdigit(c)) {
hasDigits = true;
if (hasExp) expHasDigits = true;
}
else if (c == '+' || c == '-') {
if (i > 0 && str[i-1] != 'e' && str[i-1] != 'E')
return false;
}
else if (c == '.') {
if (hasDot || hasExp) return false;
hasDot = true;
}
else if (c == 'e' || c == 'E') {
if (hasExp || !hasDigits) return false;
hasExp = true;
expHasDigits = false;
}
else {
return false;
}
}
return hasDigits && expHasDigits;
}
};
Detreministic Finite Automaton
Implement validation through explicit state transitions:
class DFANumericValidator {
public:
enum State {
INIT,
SIGN_MANTISSA,
INTEGER,
DOT_AFTER_INT,
DOT_BEFORE_INT,
DECIMAL,
EXPONENT,
SIGN_EXPONENT,
EXP_DIGITS
};
enum Symbol {
DIGIT,
DOT,
EXP,
SIGN,
OTHER
};
Symbol classify(char ch) {
if (ch >= '0' && ch <= '9') return DIGIT;
if (ch == '.') return DOT;
if (ch == 'e' || ch == 'E') return EXP;
if (ch == '+' || ch == '-') return SIGN;
return OTHER;
}
bool isValid(string str) {
unordered_map<State, unordered_map<Symbol, State>> table = {
{INIT, {{DIGIT, INTEGER}, {DOT, DOT_BEFORE_INT}, {SIGN, SIGN_MANTISSA}}},
{SIGN_MANTISSA, {{DIGIT, INTEGER}, {DOT, DOT_BEFORE_INT}}},
{INTEGER, {{DIGIT, INTEGER}, {DOT, DOT_AFTER_INT}, {EXP, EXPONENT}}},
{DOT_AFTER_INT, {{DIGIT, DECIMAL}, {EXP, EXPONENT}}},
{DOT_BEFORE_INT, {{DIGIT, DECIMAL}}},
{DECIMAL, {{DIGIT, DECIMAL}, {EXP, EXPONENT}}},
{EXPONENT, {{DIGIT, EXP_DIGITS}, {SIGN, SIGN_EXPONENT}}},
{SIGN_EXPONENT, {{DIGIT, EXP_DIGITS}}},
{EXP_DIGITS, {{DIGIT, EXP_DIGITS}}}
};
State cur = INIT;
for (char ch : str) {
Symbol sym = classify(ch);
if (table[cur].count(sym) == 0) return false;
cur = table[cur][sym];
}
return cur == INTEGER || cur == DOT_AFTER_INT ||
cur == DECIMAL || cur == EXP_DIGITS;
}
};