使用Python正则表达式从字符串中提取十进制数

时间:2017-09-13 19:52:46

标签: python regex

我尝试使用Python的重新库。 从文件中我得到几行包含以条形('|')分隔的元素。我把它们放在一个列表中,我需要的是将数字放在里面以便与它们一起运行。

这将是我要拆分的字符串之一:

>>print(line_input)
>>[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]

我打算用方括号之间的每个元素形成一个向量。

我创建了这个正则表达式

>>test_pattern="\|\[(\d*(\.\d+)?), (\d*(\.\d+)?), (\d*(\.\d+)?)]"

但结果有点令人困惑。特别是,结果是

>>vectors = re.findall(test_pattern, line_input)

>>print(vectors)
>>[('240', '', '7821', '', '0', '', '12', '', '605', '', '0', '', '3', ''), ('1.5', '.5', '7881.25', '.25', '0', '', '0', '', '0', '', '0', '', '0', ''), ('23437', '', '76611', '', '0', '', '0', '', '0', '', '605', '', '605', '')]

我不明白白色空间的来源以及为什么小数部分会重复。我知道我几乎得到它,至少,我确定这是一个简单的小细节,但我不明白。

非常感谢你。

4 个答案:

答案 0 :(得分:3)

那些空白是空的可能小数。您的vectors变量包含所有捕获组,无论是否为空。因此,当存在小数时,您将获得外部组(\d*(\.\d+)?)的一个匹配,以及内部组(\.\d+)?的一个匹配。使内部成为非捕获组:

(\d+(?:\.\d+)?)

注意:我也将其更改为要求小数点前的数字(如果有)。

答案 1 :(得分:1)

另一种方法(如果输入格式不同可能是非健壮的)这样做的方法是将字符串拆分为'] | ['来获取列表,然后拆分','来获取值:

from decimal import Decimal
input_str = '[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]'

# ignore the first and last '[' and ']' chars, then split on list separators
list_strs = input_str[1:-1].split(']|[')

# Split on ', ' to get individual decimal values
int_lists = [[Decimal(i) for i in s.split(', ')] for s in list_strs]

# int_lists contains a list of lists of decimal values, like the input format

for l in int_lists:
    print(', '.join(str(d) for d in l))

<强>结果

240, 7821, 0, 12, 605, 0, 3
1.5, 7881.25, 0, 543, 876, 0, 121
237, 761, 0, 61, 7, 605, 605

答案 2 :(得分:1)

regex有它的位置。但是,使用pyparsing编写的语法通常更容易编写 - 并且更易于阅读。

>>> import pyparsing as pp

这些数字就像用数字和句号/句号字符组成的单词。它们可选地后跟逗号,我们可以简单地压制它们。

>>> number = pp.Word(pp.nums+'.') + pp.Optional(',').suppress()

其中一个列表包含一个左方括号,我们将其取消,后跟一个或多个数字(如刚定义的那样),然后是右方括号,我们也会抑制它,然后是可选的条形字符,抑制。 (顺便说一下,这个条在某种程度上是多余的,因为右括号会关闭列表。)

我们将Group应用于整个构造,以便pyparsing将我们未被压缩的项目组织到我们的单独Python列表中。

>>> one_list = pp.Group(pp.Suppress('[') + pp.OneOrMore(number) + pp.Suppress(']') + pp.Suppress(pp.Optional('|')))

整个列表集只是一个或多个列表。

>>> whole = pp.OneOrMore(one_list)

这是输入,

>>> line_input = '[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]'

...我们将其解析为结果r

>>> r = whole.parseString(line_input)

我们可以显示结果列表。

>>> r[0]
(['240', '7821', '0', '12', '605', '0', '3'], {})
>>> r[1]
(['1.5', '7881.25', '0', '543', '876', '0', '121'], {})
>>> r[2]
(['237', '761', '0', '61', '7', '605', '605'], {})

更有可能的是,我们希望数字为数字。在这种情况下,我们知道列表中的字符串表示浮点数或整数。

>>> for l in r.asList():
...     [int(_) if _.isnumeric() else float(_) for _ in l]
... 
[240, 7821, 0, 12, 605, 0, 3]
[1.5, 7881.25, 0, 543, 876, 0, 121]
[237, 761, 0, 61, 7, 605, 605]

答案 3 :(得分:0)

你可以试试这个:

import re
s = "[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]" 
data = re.findall("\d+\.*\d+", s)

输出:

['240', '7821', '12', '605', '1.5', '7881.25', '543', '876', '121', '237', '761', '61', '605', '605']