-
-
Notifications
You must be signed in to change notification settings - Fork 46.5k
/
Copy pathstring_is_valid_number.py
170 lines (146 loc) · 4.44 KB
/
string_is_valid_number.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
"""
Solution By: Reniz Shah
Topic: Deterministic Finite Automaton (DFA)
Given a string s, return whether s is a valid number or not
Leetcode link: https://leetcode.com/problems/valid-number/description/
"""
from enum import Enum
class CharType(Enum):
NUMERIC = "NUMERIC"
SIGN = "SIGN"
EXPONENT = "EXPONENT"
DECIMAL = "DECIMAL"
class State(Enum):
INITIAL = "INITIAL"
SIGNED = "SIGNED"
WHOLE = "WHOLE"
FRACTIONAL = "FRACTIONAL"
FRACTION = "FRACTION"
EXPONENTIAL = "EXPONENTIAL"
EXP_SIGN = "EXP_SIGN"
EXP_NUMBER = "EXP_NUMBER"
state_machine: dict[State, dict[CharType, State]] = {
State.INITIAL: {
CharType.NUMERIC: State.WHOLE,
CharType.SIGN: State.SIGNED,
CharType.DECIMAL: State.FRACTIONAL,
},
State.SIGNED: {CharType.NUMERIC: State.WHOLE, CharType.DECIMAL: State.FRACTIONAL},
State.WHOLE: {
CharType.NUMERIC: State.WHOLE,
CharType.DECIMAL: State.FRACTION,
CharType.EXPONENT: State.EXPONENTIAL,
},
State.FRACTIONAL: {CharType.NUMERIC: State.FRACTION},
State.FRACTION: {
CharType.NUMERIC: State.FRACTION,
CharType.EXPONENT: State.EXPONENTIAL,
},
State.EXPONENTIAL: {
CharType.NUMERIC: State.EXP_NUMBER,
CharType.SIGN: State.EXP_SIGN,
},
State.EXP_SIGN: {CharType.NUMERIC: State.EXP_NUMBER},
State.EXP_NUMBER: {CharType.NUMERIC: State.EXP_NUMBER},
}
def classify_char(char: str) -> CharType | None:
"""
Classifies a character into one of the following categories:
- 'CharType.NUMERIC': if the character is a digit (0-9)
- 'CharType.SIGN': if the character is a plus sign (+) or a minus sign (-)
- 'CharType.EXPONENT': if the character is an 'e' or 'E'
(used in exponential notation)
- 'CharType.DECIMAL': if the character is a decimal point (.)
- None: if the character does not fit into any of the above categories
- None: if size of char is not 1
Parameters:
char (str): The character to be classified
Returns:
CharType: The classification of the character
>>> classify_char('2')
<CharType.NUMERIC: 'NUMERIC'>
>>> classify_char('-')
<CharType.SIGN: 'SIGN'>
>>> classify_char('e')
<CharType.EXPONENT: 'EXPONENT'>
>>> classify_char('.')
<CharType.DECIMAL: 'DECIMAL'>
>>> classify_char('')
>>> classify_char('0')
<CharType.NUMERIC: 'NUMERIC'>
>>> classify_char('01')
"""
if len(char) != 1:
return None
if char.isdigit():
return CharType.NUMERIC
if char in "+-":
return CharType.SIGN
if char in "eE":
return CharType.EXPONENT
if char == ".":
return CharType.DECIMAL
return None
def is_valid_number(number_string: str) -> bool:
"""
This function checks if the input string represents a valid number.
It uses a finite state machine to parse the input string,
transitioning between states based on the character type.
The function returns True if the input string represents a valid number,
and False otherwise.
A valid number is defined as a string that can be parsed into an
integer, decimal, or exponent.
>>> is_valid_number("2")
True
>>> is_valid_number("0089")
True
>>> is_valid_number("-0.1")
True
>>> is_valid_number("+3.14")
True
>>> is_valid_number("4.")
True
>>> is_valid_number("-.9")
True
>>> is_valid_number("2e10")
True
>>> is_valid_number("-90E3")
True
>>> is_valid_number("3e+7")
True
>>> is_valid_number("+6e-1")
True
>>> is_valid_number("53.5e93")
True
>>> is_valid_number("-123.456e789")
True
>>> is_valid_number("abc")
False
>>> is_valid_number("1a")
False
>>> is_valid_number("1e")
False
>>> is_valid_number("e3")
False
>>> is_valid_number("99e2.5")
False
>>> is_valid_number("--6")
False
>>> is_valid_number("-+3")
False
>>> is_valid_number("95a54e53")
False
>>> is_valid_number(".")
False
"""
valid_final_states = {State.WHOLE, State.FRACTION, State.EXP_NUMBER}
current_state = State.INITIAL
for char in number_string:
char_type = classify_char(char)
if char_type is None or char_type not in state_machine[current_state]:
return False
current_state = state_machine[current_state][char_type]
return current_state in valid_final_states
if __name__ == "__main__":
import doctest
doctest.testmod()