python:提取匹配模式的更好方法?

时间:2017-02-15 22:01:41

标签: python

我有一些如下代码。它会搜索文件中的每一行以查找某些模式,如果找到,则从匹配的模式中提取一些字符串。每行只能匹配一个模式(如果有的话)。文件中的内容只是文本行,有些行有hight = 123,有些中等= 123,有些低= 123。

with open(file) as r:
    for line in r:
        if re.search('high=\d+', line):
             p = re.search('high=(\d+)', line)
             high = p.group(1)
        elif re.search('medium=\d+', line):
             p = re.search('medium=(\d+)', line)
             medium = p.group(1)
        elif re.search('low=\d+', line):
             p = re.search('low=(\d+)', line)
             low = p.group(1)
        ...

现在我想知道我是否可以在不进行第二次搜索的情况下提取匹配的部分,如下所示,其中一些无效代码作为示例。搜索的模式可能彼此完全不同。这里的问题是,在re.search()返回true之后是否有提取匹配部分的方法。

with open(file) as r:
    for line in r:
        if re.search('high=(\d+)', line):
            high = _.group(1)    # invalid code, but looking for something like this.
        elif re.search('medium=(\d+)', line):
            medium = _.group(1)  # invalid code
        elif re.search('low=(\d+)', line):
            low = _.group(1)     # invalid code
        ...

注意我本可以做到以下,但那不是我想要的。

with open(file) as r:
    for line in r:
        m = re.search('high=(\d+)', line)
        if m:
             high = m.group(1)
        else:
             m = re.search('medium=(\d+)', line)
             if m:
                 medium = m.group(1)
             else:
                 m = re.search('low=(\d+)', line)
                 if m:
                    low = m.group(1)
        ...

我曾尝试先编译模式,例如以下内容,但我收到了错误" NameError:name' _'未定义"。我用python2和python3试过这个。在_.group(1)中有一些奇特的行为(在某些情况下它起作用)。我可以在另外的帖子中提出这个问题。

h = re.compile('hight=(\d+)')
m = re.compile('medium=(\d+)')
l = re.compile('low=(\d+)')

with open(file) as r:
    for line in r:
        if h.search(line):
            high = _.group(1)
        elif m.search(line):
            medium = _.group(1)
        elif l.search(line):
            low = _.group(1)
        ...

2 个答案:

答案 0 :(得分:2)

你可以试试这个

import re
r = re.compile("(high|medium|low)=(\d+)")
with open(file) as f:
    for line in f:
        match = r.search(line)
        if not match:
            continue
        lvl, val = match.groups()
        if lvl == "high":
            high = val
        elif lvl == "medium":
            medium = val
        elif lvl == "low":
            low = val

答案 1 :(得分:2)

当您在交互式shell中工作时,

_保存最后执行的语句的结果。它只是程序环境中的一个普通变量。

因此,如果您不想再次进行搜索,则必须存储匹配对象,就像在第3个代码示例中一样。

如果您想避免嵌套ifs,可以使用continue:

with open(file) as r:
    for line in r:
        m = re.search('high=(\d+)', line)
        if m:
            high = m.group(1)
            continue
        m = re.search('medium=(\d+)', line)
        if m:
            medium = m.group(1)
            continue
        m = re.search('low=(\d+)', line)
        if m:
            low = m.group(1)
            continue
        ...

编辑,回答你的评论:

在Python中没有通用的方法可以做你想做的事情:

  • 您没有自动将结果分配给变量,例如Perl,

  • 你不能写

    如果xxx = yyy:

避免写错=而不是==

尽管如此,总有一种方法可以做到:

import re


class Matcher:
    def __init__(self, pattern):
        self._pattern = pattern
        self._compiled_pattern = re.compile(pattern)
        self._match = None

    def __str__(self):
        return '<Matcher> %s, matching %s' % (self._pattern, self._match)

    # match and search apply on the regex, and return the match object   
    def match(self, string):
        self._match = self._compiled_pattern.match(string)
        return self._match

    def search(self, string):
        self._match = self._compiled_pattern.search(string)
        return self._match

    # Other methods apply to the match object
    def __getattr__(self, attr):
        return  getattr(self._match, attr)



if __name__ == '__main__':

    # instead of m = re.compile(...)
    m = Matcher(r'(high)=(\d+)')

    lines = ['high=4', 'nothing here']


    for line in lines:
        # you can use search and match just like on the re object
        if m.search(line):
            # then you can use all methods of Match objects
            print(m.groups())
            print(m.group(1), m.group(2))
            print(m.span())

所以,它似乎表现得像你想要的那样!