1

问题

我有一个包含不同数字、数学符号和单词的字符串,例如

str = ".1**2 + x/(10.0 - 2.E-4)*n_elts"

我想提取所有数字并保留数字之间的部分,以便以后可以再次将它们放在一起(在处理数字之后)。

lst = [".1", "**", "2", " + ", "x/(", "10.0", " - ", "2.E-4", ")*n_elts"]

将是许多可接受的结果之一。不是数字的元素可以以任意方式进一步拆分,因为下一步将是

"".join(process(l) for l in lst)

过程可能看起来像这样(欢迎提出更好的检查方法l的建议):

def process(l):
    try:
        n = float(l)
    except ValueError:
        return l
    else:
        return work_on_it(l)

当前状态:

这个答案中,我想出了如何保留分隔符并努力做到

lst = re.split('( |\+|\-|\*|/)', ".1**2 + x/(10.0 - 2.E-4)*n_elts")

现在我需要以某种方式避免拆分2.E-4.

我试图制定一个覆盖所有可能出现和思考的数字的正则表达式(vi 语法,希望这是通用的)

\d*\.\d*[E|e]*[|+|-]*\d*

应该可以。

一种策略是以某种方式将其纳入re.

我还找到了一个相关的答案,似乎在做数字匹配部分。它可能比我需要的复杂一点,但主要是我不知道如何将它与保留分隔符位结合起来。

4

2 回答 2

2

一个一般说明:在您不使用的字符类中|,因为它只是被视为要匹配的另一个字符。在字符类中,允许的字符简单地一个接一个地列出。

要实际解决您的问题:既然您仍然保留分隔符,那么匹配数字还是非数字并不重要吗?所以简单地使用

lst = re.split(r'(\d*\.\d*[Ee]*[+-]*\d*)', ".1**2 + x/(10.0 - 2.E-4)*n_elts")

不过,您可能希望稍微改进一下该数字正则表达式:

lst = re.split(r'((?:\d+\.\d*|\.?\d+)(?:[Ee][+-]?\d+)?)', ".1**2 + x/(10.0 - 2.E-4)*n_elts")

这样,您可以将小数点设为可选,但在它之前或之后至少需要一位数字。这也使得指数部分完全是可选的,但如果它存在则确保它的格式正确。?:抑制捕获。否则,那些内部组将与外部括号集执行相同的操作,并将内部匹配的部分添加到结果中split- 但是您不希望这样,因为这会给您完整的数字,即指数之前的部分, 和指数分别。所以你需要使用?:来抑制捕获(这通常是一个好习惯,除非你明确需要捕获)。

最后,注意原始字符串的使用(r前面的字符串文字)。没有这种转义可能会变得非常丑陋(因为您可能必须双重转义某些正则表达式元字符)。在 Python 中,您应该始终使用原始字符串来表示正则表达式模式。

于 2013-05-05T23:53:55.233 回答
2

您可以利用re.split()捕获正则表达式在奇数索引处返回匹配项来利用它,例如

import re

s = ".1**2 + x/(10.0 - 2.E-4)*n_elts"
parts = re.split(r"([+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)", s)
parts[1::2] = [str(100 * float(f)) for f in parts[1::2]]
print("".join(parts))
# -> 10.0**200.0 + x/(1000.0 - 0.02)*n_elts

其中正则表达式来自Python 和正则表达式问题,提取 float/double value

于 2013-05-06T01:32:57.587 回答