使用正则表达式可能会为您提供最简洁的代码来解决此问题。很难超越其简洁性。
re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", str)
来自pythad的答案。
然而,你说“我试图避免使用正则表达式”,所以这里提供一种不使用正则表达式的解决方案。显然,这种解决方案比使用正则表达式的解决方案要长一些(可能慢得多),但它并不复杂。
该代码逐个字符地循环输入。每次从字符串中获取一个字符时,如果将其附加到current
(一个保存当前正在解析的数字的字符串)仍然保持有效数字,则将其附加到current
中。当它遇到无法附加到current
的字符时,只有在current
本身不是''
、'.'
、'-'
或'-.'
之一时,才将current
保存到数字列表中;这些是可以潜在地开始一个数字但本身不是有效数字的字符串。
保存current
时,会删除尾随的'e'
、'e-'
或'e+'
。例如,对于这样的字符串'1.23eA'
,将会发生这种情况。在解析该字符串时,current
最终将变为'1.23e'
,但随后遇到'A'
,这意味着该字符串不包含有效的指数部分,因此将丢弃'e'
。
保存current
之后,将其重置。通常情况下,current
被重置为''
,但当触发保存current
的字符是'.'
或'-'
时,current
被设置为该字符,因为这些字符可能是一个新数字的开头。
这里是函数extract_numbers(s)
。在return numbers
之前的那一行将字符串列表转换为整数和浮点数值的列表。如果只想要字符串,可以删除那一行。
def extract_numbers(s):
"""
Extract numbers from a string.
Examples
--------
>>> extract_numbers("Hello4.2this.is random 24 text42")
[4.2, 24, 42]
>>> extract_numbers("2.3+45-99")
[2.3, 45, -99]
>>> extract_numbers("Avogadro's number, 6.022e23, is greater than 1 million.")
[6.022e+23, 1]
"""
numbers = []
current = ''
for c in s.lower() + '!':
if (c.isdigit() or
(c == 'e' and ('e' not in current) and (current not in ['', '.', '-', '-.'])) or
(c == '.' and ('e' not in current) and ('.' not in current)) or
(c == '+' and current.endswith('e')) or
(c == '-' and ((current == '') or current.endswith('e')))):
current += c
else:
if current not in ['', '.', '-', '-.']:
if current.endswith('e'):
current = current[:-1]
elif current.endswith('e-') or current.endswith('e+'):
current = current[:-2]
numbers.append(current)
if c == '.' or c == '-':
current = c
else:
current = ''
numbers = [float(t) if ('.' in t or 'e' in t) else int(t) for t in numbers]
return numbers