1

文字列からすべての日付 (おそらく異なる形式で書かれている) を解析しようとしています。問題は、d/m -yたとえば 22/11 -12 のように、この形式で日付が書き込まれる可能性があることです。しかし、年が指定されていないこの形式で書かれた日付もある可能性がありd/mます。この文字列で長い形式を含む日付が見つかった場合、短い形式で再び検出されることは望ましくありません。これは私のコードが失敗する場所です。最初の日付が 2 回検出されます (1 回は年があり、1 回は年がありません)。

本当に 2 つの質問があります: (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()
4

3 に答える 3

2

2番目の正規表現で使用して、後に続く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})'
)

したがって、正規表現で一致する日付は、2番目の日付では一致しfirstません。

于 2012-11-22T21:08:39.800 に答える
2

ふたつのやり方:

  1. 単一の正規表現を使用し、| を使用します。すべてのケースを結合する演算子:

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

  2. 単一のインスタンスのみを検索し、次の検索の「開始位置」を渡します。どの形式が選択されていても、常に最も早い一致から開始する必要があるため、これは複雑になることに注意してください。つまり、3 つの一致すべてをループし、どれが最も早い一致かを判断し、置換を実行してから、開始位置をインクリメントしてもう一度実行します。これにより、オプション 1 がはるかに簡単になります。

いくつかの追加ポイント:

  1. 「生の文字列」を使用していることを確認してください。各文字列の前に「r」を追加してください。そうしないと、「\」文字が食べ尽くされて RE エンジンに渡されないリスクがあります

  2. finditer ではなく、「repl」パラメーターの代わりに「sub」とコールバック関数を使用して置換を行うことを検討してください。この場合の「repl」には一致オブジェクトが渡され、置換文字列を返す必要があります。

  3. その代替が選択されていない場合、「単一の」 re 内の一致するグループの値は None になり、どの代替が使用されたかを簡単に検出できます。

  4. その変数を変更するつもりがない限り、「グローバル」と言うべきではありません。

これは、完全で機能するコードです。

#!/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
于 2012-11-22T21:08:09.230 に答える
1

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
于 2012-11-22T21:10:08.223 に答える