>我想匹配字符串中的数字(int和real),但如果它们是标识符的一部分,则不匹配;例如,我想匹配5.5或42,但不是x5。字符串大致采用"x5*1.1+42*y=40"的形式。 到目前为止,我想出了
([0-9]*[.])?[0-9]+[^.*+=<>]
这正确地忽略了 x0,但也忽略了 0 或 0.5(但是 12.45 有效)。将+
更改为*
会导致错误的匹配。
如果有人能指出我的错误,那就太好了。
谢谢!
这其实并不简单。 浮点文字比您想象的要复杂,能够包含指数格式的e
或E
。 此外,您可以为数字和/或指数添加前缀符号(+
或-
)。 总而言之,它可以像这样完成:
re.findall(r'(?:(?<![a-zA-Z_0-9])|[+-]s*)[d.]+(?:[eE][+-]?d+)?',
'x5*1.1+42*y=40+a123-3.14e-2')
这将返回:
['1.1', '+42', '40', '-3.14e-2']
你应该考虑像4+3
这样的事情是否应该导致['4', '3']
或['4', '-3']
。 如果输入是4+-3
显然'-3'
更可取。 但是要区分这些并不容易,您应该考虑为这些使用适当的公式解析器。
也许标准模块ast
可以帮助您。 在这种情况下,表达式必须是有效的 Python 表达式,因此不允许使用a+b=40
之类的东西,因为等号的左侧不是正确的左值。 但是对于有效的 Python 对象,您可以使用这样的ast
:
import ast
def find_all_numbers(e):
if isinstance(e, ast.BinOp):
for r in find_all_numbers(e.left):
yield r
for r in find_all_numbers(e.right):
yield r
elif isinstance(e, ast.Num):
yield e.n
list(find_all_numbers(ast.parse('x5*1.1+42*y-40').body[0].value))
返回:
[1.1, 42, 40]
你可以用类似的东西来做到这一点
bd*(.d+)?b
它匹配任意数量的数字(d*
),后跟可选的小数部分((.d+)?
)。b
匹配单词边界,即单词字符和非单词字符之间的位置。而且由于数字和(英文)字母都是单词字符,因此它不会像x5
这样的序列中的5
匹配。
请参阅此正则表达式 101 示例。
您的尝试失败的主要原因是它以[^.*+=<>]
结尾,这要求数字(或更确切地说是匹配)以.
、*
、=
、+
、<
或>
以外的字符结尾。当以单个数字结尾时,如0
和0.5
,该数字被[0-9]+
吃掉,并且没有与剩下的[^.*+=<>]
相匹配,因此它失败了。在12.45
的情况下,它首先匹配12.4
然后[^.*+=<>]
匹配5
。
执行类似((?<![a-zA-Z_])d+(.d+)?)
的操作它使用负回溯,以便不选择任何在其之前具有[a-zA-Z_]
的内容。 在正则表达式 101 中查看它。
关于您的正则表达式([0-9]*[.])?[0-9]+[^.*+=<>]
使用[0-9]+
而不是[0-9]*
,因为它不允许捕获 .05,只有 0.5。另一件事是[^.*+=<>]
这部分,您可以添加 ?到最后,以便允许它也没有字符。示例1.1
不会被捕获,因为([0-9]*[.])?[0-9]+
满意,但也不会[^.*+=<>]
它之后