Python正则表达式搜索数字和小数

5

我正在尝试使用Python的正则表达式提取数字值(100.00和200.00),但是当我调用代码时,它没有产生任何结果... 我使用的是Python 2.7版本。

1)我的文件名为“file100”,需要从中选择值。

# cat file100
Hi this doller 100.00
Hi this is doller 200.00

2) 这是我的Python代码...

# cat count100.py
#!/usr/bin/python
import re
file = open('file100', 'r')
for digit in file.readlines():
        myre=re.match('\s\d*\.\d{2}', digit)
        if myre:
           print myre.group(1)

3) 当我运行这段代码时,它没有返回任何结果,也没有错误提示。

# python   count100.py

Pygo,你觉得我的回答有帮助吗? - Russia Must Remove Putin
附注:for digit in file.readlines():是浪费且延迟处理的(在开始迭代之前,它会将整个文件读入内存)。for digit in file:迭代而不是读入内容(因此峰值内存基于最大输入行而不是文件大小)。实际上没有使用file.readlines()的情况;在极少数需要列表行而不是逐行迭代时,list(file)以更通用/简洁的方式完成相同的结果(它适用于任何非无限迭代器,而不仅仅是具有.readlines()的类似文件的对象)。 - ShadowRanger
1
@ShadowRanger,我在下面的回答中提到了这一点。 - Russia Must Remove Putin
我不知道你为什么要使用 group(1),因为你的正则表达式中没有捕获组。我相信我已经简明扼要地解释了为什么你应该只使用 group(0) - Russia Must Remove Putin
4个回答

2
请使用re.search代替:
import re
file = open('file.txt', 'r')
for digit in file.readlines():
    myre = re.search(r'\s\b(\d*\.\d{2})\b', digit)
    if myre:
        print myre.group(1)

Results

100.00
200.00

文档中得知:

扫描字符串,查找正则表达式模式第一次产生匹配的位置。

如果您决定使用组,则还需要使用括号

(...) 匹配括号内的任何正则表达式,并指示组的开始和结束;在执行匹配后,可以检索组的内容,并且可以使用 \number 特殊序列在字符串中稍后匹配。要匹配文字“(”或“)”,请使用(或),或将它们括在字符类中:[(] [)]。

re.match 仅在以下情况下有效:

如果字符串的开头有零个或多个字符与正则表达式模式匹配

请使用 rregex 括起来作为原始字符串

字符串字面值可以选择以字母'r'或'R'作为前缀;这样的字符串被称为原始字符串,并使用不同的规则来解释反斜杠转义序列。

...

除非字符串中有'r'或'R'前缀,否则字符串中的转义序列将按照类似于标准C使用的规则进行解释。

它不使用上下文管理器,将整个文件实例化到内存中,并且每次在循环中重新编译正则表达式。digit 语义上也是错误的。 - Russia Must Remove Putin
1
仅解决 OP 的主要问题,这不是一个代码修订工具,当然它可以在很多方面得到改进,但这不是重点...干杯 - Juan Diego Godoy Robles
2
问题是为什么它不起作用,@klashxx给出的答案解释了原因。如果您想改进答案,可以将其作为单独的答案给出,为什么要将其投票降低呢? - helloV
@klashxx - 这个优化后的代码运行得很好,虽然我正在寻找正则表达式前面 'r' 的字面意思,与此同时我会从 Python 官网上阅读相关内容。 - Karn Kumar
1
r 使字符串成为原始字符串,因此当 Python 解析字符串时,反斜杠不会转义它们前面的字符。 - Russia Must Remove Putin

1
如果它们总是出现在您的行末,只需进行一次rsplit并提取最后一个元素即可:
with open('file100', 'r') as f:
    for line in f:
        print(line.rsplit(None, 1)[1])

输出:

100.00
200.00

rsplit(None,1) 的意思是我们从字符串末尾的空格处分割一次,然后获取第二个元素:

In [1]: s = "Hi this doller 100.00"

In [2]: s.rsplit(None,1)
Out[2]: ['Hi this doller', '100.00']

In [3]: s.rsplit(None,1)[1]
Out[3]: '100.00'

In [4]: s.rsplit(None,1)[0]
Out[4]: 'Hi this doller'

如果你真的需要一个正则表达式,使用search
import re

with open('file100', 'r') as f:
    for line in f:
        m = re.search(r"\b\d+\.\d{2}\b",line)
        if m:
            print(m.group())

你假设数字前始终有一个空格。 - Russia Must Remove Putin
@AaronHall,你有没有看过原帖中的模式? - Padraic Cunningham
@Padraic - 它能工作,但我希望能用正则表达式来完成。你能解释一下下面的代码吗?(None, 1)[1] - Karn Kumar
@pygo,我添加了一个例子,希望它能让事情更清晰明了。 - Padraic Cunningham
1
@Padraic - 这是非常好的解释。 - Karn Kumar

1
你的主要问题是使用了re.match,它要求从字符串开头开始匹配,而不是re.search,它允许从任意位置开始匹配。我将详细说明我的建议:
import re

不需要在每个循环中重新编译(Python实际上会为您缓存一些正则表达式,但请将其中一个引用保留以确保安全)。我正在使用VERBOSE标志来分解正则表达式。使用r在字符串前面,这样反斜杠就不会作为Python读取字符串时的转义字符:
regex = re.compile(r'''
  \s      # one whitespace character, though I think this is perhaps unnecessary
  \d*     # 0 or more digits
  \.      # a dot
  \d{2}   # 2 digits
  ''', re.VERBOSE) 

使用上下文管理器并以通用换行符 ''rU'' 模式打开文件,这样无论在什么平台上创建文件,都能按行读取它。
with open('file100', 'rU') as file:

不要使用readlines,它会一次性将整个文件加载到内存中。相反,使用文件对象作为迭代器:
    for line in file:
        myre = regex.search(line) 
        if myre:
            print(myre.group(0)) # access the first group, there are no  
                                 # capture groups in your regex

我的代码输出:
100.00
200.00

简要而清晰地解释一下,我是新手,所以仍在学习Python的过程中。 - Karn Kumar
如果你喜欢这个回答,你可以点赞,如果它是最好的解答,请选择接受它。 - Russia Must Remove Putin
@ Aaron - 为什么我们要使用re.compile,它是必要的吗,还是可以省略掉。 它的用途是什么。我还想知道你在以前的评论中提到的"上下文管理器"是什么意思,这是你在谈论内存上下文吗? - Karn Kumar
@pygo 正则表达式字符串在搜索中使用之前必须进行编译。如果您不使用预编译的正则表达式,则语义是您正在每个循环重新编译搜索。最佳实践是将冗余代码分离和提取出内部循环。这不会增加代码复杂性,事实上,在大型程序的上下文中,它会减少代码复杂性。 - Russia Must Remove Putin

-1

这里有几个问题:

  1. .match 只会在字符串开头查找匹配项 -- 请参见 search() vs. match()

  2. 您没有使用捕获组,因此 myre.group(1).group(1) 没有任何内容。

以下是更新后的示例:

import re

file = """
Hi this doller 100.00
Hi this is doller 200.00
"""

for digit in file.splitlines():
    myre = re.search('\s\d*\.\d{2}', digit)
    if myre:
        print(myre.group(0))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接