【题目】:验证输入的字符串能否正确地转换成合法的数字
Validate if a given string is numeric.
Some examples:
"0"
=> true
" 0.1 "
=> true
"abc"
=> false
"1 a"
=> false
"2e10"
=> true
Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one.
【分析】:此题需要判断的情况非常多,若直接判断,所耗时间较多;若采用确定有穷状态自动机(DFA)来解决此题,简洁优雅。【方法1】:参考http://blog.csdn.net/ljiabin/article/details/44980109
思路:把字符串分三段(小数点前、小数点与e/E之间部分、e/E之后),这三段都必须为纯数字组成的字符串。注意,第一部分和第三部分可以带符号(如+12.34e-56),第一部分和第二部分可以有一部分为空(如“.2"或"2.")。
- 去掉首尾多余的空格;
- 去掉开头的正负号;
- 看有没有e或E,如果有那么e/E后面只能是整数;
- 再看e前面的部分有没有小数点,小数点前后两部分都必须为整数。
【Python代码】:
def isNumber(self, s):
"""
:type s: str
:rtype: bool
"""
s = s.strip()
if len(s) == 0:
return False
if s[0] in ['+', '-']:
s = s[1:]
if 'e' in s or 'E' in s: #若包含三部分,则先判断第三部分
e_pos = s.find('e') if 'e' in s else s.find('E')
post_e = s[e_pos+1:]
if len(post_e) == 0:
return False
elif post_e[0] in ['+', '-']:
post_e = post_e[1:]
if not post_e.isdigit():
return False
else:
s = s[:e_pos]
if '.' in s: #此时,只包含第一、第二部分,判断第一和第二部分
substring = s.split('.', 1)
pre_dot = substring[0]
try:
post_dot = substring[1]
except IndexError: post_dot = ''
if pre_dot == '' and post_dot == '':
return False
elif not pre_dot.isdigit() and not post_dot.isdigit():
return False
elif pre_dot.isdigit() and post_dot == '':
return True
elif pre_dot== '' and post_dot.isdigit():
return True
elif pre_dot.isdigit() and post_dot.isdigit():
return True
return s.isdigit() #此时只包含第一部分
【方法2】:参考
https://zhuanlan.zhihu.com/simons/20042325和
https://www.cnblogs.com/zuoyuan/p/3703075.html
构建以下的DFA:
- 0 初始无输入或者只有space的状态
- 1 输入了数字之后的状态
- 2 前面无数字,只输入了dot的状态
- 3 输入了+/-状态
- 4 前面有数字和有dot的状态
- 5 'e' or 'E'输入后的状态
- 6 输入e之后输入+/-的状态
- 7 输入e后输入数字的状态
- 8 前面有有效数输入之后,输入space的状态
只有1,4,7,8四种状态是合法的
【Python代码】:
def isNumber2(self, s):
INVALID = 0
SPACE = 1
SIGN = 2
DIGIT = 3
DOT = 4
EXPONENT = 5
# transitionTable 表示邻接矩阵,行表示的是0-8九个状态,列表示的是五种不同的输入,邻接矩阵中的值表示在不同的状态下接受不同的输入会达到怎样的状态,如transitionTable[0][0]此时在图中第0种状态 (no input or just spaces)时,若输入的值是INVALID,则值为-1,表示无效。若transitionTable[1][3]表示此时在图中第1种状态(input is digit)时,输入的值为DIGIT,则会跳转到图中第4种状态(digits and dot in front)
transitionTable = [[-1,0,3,1,2,-1], #0 no input or just spaces
[-1, 8, -1, 1, 4, 5], #1 input is digits
[-1, -1, -1, 4, -1, -1], #2 no digits in front just Dot
[-1, -1, -1, 1, 2, -1], #3 sign
[-1, 8, -1, 4, -1, 5], #4 digits and dot in front
[-1, -1, 6, 7, -1, -1], #5 input 'e' or 'E'
[-1, -1, -1, 7, -1, -1], #6 after 'e' input sign
[-1, 8, -1, 7, -1, -1], #7 after 'e' input digits
[-1, 8, -1, -1, -1, -1]] #8 after valid input input space
state = 0
for c in s:
inputtype = INVALID
if c == ' ':
inputtype = SPACE
elif c in ['+', '-']:
inputtype = SIGN
elif c.isdigit():
inputtype = DIGIT
elif c == '.':
inputtype = DOT
elif c in ['e', 'E']:
inputtype = EXPONENT
state = transitionTable[state][inputtype]
if state == -1:
return False
return state == 1 or state == 4 or state == 7 or state == 8