确保两个正则表达式不会找到相同的结果

2024-10-01 17:40:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图从一个字符串中解析出所有日期(可能以不同的形式编写)。问题是可能有一个日期是用这种形式写的d/m -y例如22/11-12。但是也可以用这种形式写一个日期d/m,没有指定年份。如果我在这个字符串中找到一个包含较长形式的日期,我不希望它以较短的形式再次被找到。这就是我的代码失败的地方,它会两次找到第一个日期(一次有年份,一次没有年份)。你知道吗

我真的有两个问题:(1)“正确”的方法是什么。我似乎从错误的角度来看待这个问题。(2) 如果我坚持这样做,为什么这行datestring.replace(match.group(0), '')不删除日期,这样我就不能再被找到了?你知道吗

这是我的密码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

dformats = (
    '(?P<day>\d{1,2})/(?P<month>\d{1,2}) -(?P<year>\d{2})',
    '(?P<day>\d{1,2})/(?P<month>\d{1,2})',
    '(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
            )


def get_dates(datestring):
    """Try to extract all dates from certain strings.

    Arguments:
    - `datestring`: A string containing dates.
    """
    global dformats

    found_dates = []

    for regex in dformats:
        matches = re.finditer(regex, datestring)
        for match in matches:
            # Is supposed to make sure the same date is not found twice
            datestring.replace(match.group(0), '')

            found_dates.append(match)
    return found_dates

if __name__ == '__main__':
    dates = get_dates('1/2 -13, 5/3 & 2012-11-22')
    for date in dates:
        print date.groups()

Tags: 字符串infordatematchgroupreplace形式
3条回答

您可以sub而不是find

def find_dates(s):

    dformats = (
        '(?P<day>\d{1,2})/(?P<month>\d{1,2}) -(?P<year>\d{2})',
        '(?P<day>\d{1,2})/(?P<month>\d{1,2})',
        '(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
    )    

    dates = []
    for f in dformats:
        s = re.sub(f, lambda m: dates.append(m.groupdict()), s)
    return dates

两种方式:

  1. 使用一个正则表达式并使用|运算符将所有事例连接在一起:

    expr = re.compile ( r"expr1|expr2|expr3" )

  2. 只查找单个实例,然后为下一次搜索传递“起始位置”。请注意,这将使事情复杂化,因为无论选择哪种格式,您总是希望从最早的匹配开始。也就是说,循环所有三个匹配项,找出最早的匹配项,进行替换,然后以递增的起始位置再次进行。这使得选项1变得更加容易。

另外几点:

  1. 确保使用的是“原始字符串”:在每个字符串的前面加一个“r”。否则“\”字符可能会被吃掉,而不会传递给RE引擎

  2. 考虑使用“sub”和回调函数代替“repl”参数来进行替换,而不是finditer在这种情况下,“repl”被传递一个匹配对象,并且应该返回替换字符串。

  3. 如果未选择备选方案,则“单一”re中的匹配组将具有值None,这样可以很容易地检测使用了哪个备选方案。

  4. 除非您打算修改该变量,否则不应该说“global”。

下面是一些完整的工作代码。你知道吗

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

expr = re.compile(
    r'(?P<day1>\d{1,2})/(?P<month1>\d{1,2}) -(?P<year>\d{2})|(?P<day2>\d{1,2})/(?P<month2>\d{1,2})|(?P<year3>\d{4})-(?P<month3>\d{2})-(?P<day3>\d{2})')


def get_dates(datestring):
    """Try to extract all dates from certain strings.

    Arguments:
    - `datestring`: A string containing dates.
    """

    found_dates = []
    matches = expr.finditer(datestring)
    for match in matches:
        if match.group('day1'):
            found_dates.append({'day': match.group('day1'),
                                 'month': match.group('month1') })
        elif match.group('day2'):
            found_dates.append({'day': match.group('day2'),
                                'month': match.group('month2')})
        elif match.group('day3'):
            found_dates.append({'day': match.group('day3'),
                                'month': match.group('month3'),
                                'year': match.group('year3')})
        else:
            raise Exception("wtf?")
    return found_dates

if __name__ == '__main__':
    dates = get_dates('1/2 -13, 5/3 & 2012-11-22')
    for date in dates:
        print date

您可以在第二个正则表达式中使用negative look ahead,只匹配那些dates后面没有-year的正则表达式:

dformats = (
    r'(?P<day>\d{1,2})/(?P<month>\d{1,2}) -(?P<year>\d{2})',
    r'(?P<day>\d{1,2})/(?P<month>\d{1,2})(?!\s+-(?P<year>\d{2}))',
    r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
)

因此,在first正则表达式中匹配的日期将不会在第二个正则表达式中匹配。你知道吗

相关问题 更多 >

    热门问题