3

特定の日付を文字列として検証および修正するプログラムを作成しています。04121987形式の日付としましょうddmmyyyy。そのような日付の正規表現:

(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])(19\d\d|20\d\d)

文字列を正規表現と一致させると、うまく機能します。Python の場合:

>>> regex = re.compile(r'(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])(19\d\d|20\d\d)')
>>> regex.findall('04121987')
[('04', '12', '1987')]

私が文字列を持っている場合、それは有効な月ではない04721987ことがはっきりとわかるため、文字列は正規表現と一致しません。72

>>> regex.findall('04721987')
[]

私が知りたいのは、正規表現が失敗する原因となる文字とその位置です。この場合は です7。Pythonでこれを行うにはどうすればよいですか?

4

4 に答える 4

1

この解決策は野獣です。より良い方法を見つけていただければ幸いです。このコードは軽くテストされており、十分である可能性があります。errorindex() 関数は日付を文字列として取り、正しくないエントリのインデックスのリストを返します。ただし、最初の月の桁が正しくない場合はあいまいです。1桁目がわからないと、2桁目が正しいかどうか判断できません。これがコードです。注:うるう年を忘れていました!

def errorindex(s):
  err = []
  for i in range(len(s)):
    if i == 0:  #month1
      if int(s[i]) < 0 or int(s[i]) > 1:
        err.append(i)
    if i == 1:  #month2
      if int(s[i-1]) == 0:
        if int(s[i]) < 1 or int(s[i]) > 9:
          err.append(i)
      elif int(s[i-1]) == 1:
        if int(s[i]) < 0 or int(s[i]) > 2:
          err.append(i)
      else:
        if int(s[i]) < 0 or int(s[i]) > 2:
          err.append(i)
    if i == 2:  #day1
      if int(s[i]) < 0 or int(s[i]) > 3:
        err.append(i)
    if i == 3:  #day2
      if int(s[i-1]) in [0,1,2] and str(s[:2]) != '02':
        if int(s[i]) < 0 or int(s[i]) > 9:
          err.append(i)
      elif int(s[i-1]) in [0,1,2] and str(s[:2]) == '02':
        if int(s[i]) < 0 or int(s[i]) > 8:
          err.append(i)
    if i == 4:  #year1
      if int(s[i]) < 1 or int(s[i]) > 2:
        err.append(i)
    if i == 5:  #year2
      if int(s[i-1]) == 1:
        if int(s[i]) != 9:
          err.append(i)  
      elif int(s[i-1]) == 2:
        if int(s[i]) != 0:
          err.append(i)
    if i ==6:
      if int(s[i]) < 0 or int(s[i]) > 9:
        err.append(i)
    if i ==7:
      if int(s[i]) < 0 or int(s[i]) > 9:
        err.append(i)
  return err

s = '04721987'  

print(errorindex(s))
于 2013-02-05T10:32:59.430 に答える
1

_sreモジュールはCで実装されているため、あなたが望むことは不可能だと思います;(。

代わりにこのパッケージを使用することもできます(モンキー パッチsre_compileを適用したり、パスを変更したり、新しいものを最初にインポートしたりする_sreなどして)、それだけの価値があるとは思いません。これは Python で完全に記述されたパッケージの実装である_sreため、ソース コードを表示して編集し、次の文字が一致しない場合に適切な処理を行うことができます。

次のいずれかで同様のことができます。

  • 日付文字列を 3 つ (日、月、年) に分割し、正規表現を個別に照合する
  • 正規表現を含まない別の方法を使用して日時を検証する

エラーが発生した正確な数字を取得できない可能性がありますが、ユーザーに何が問題なのか (日、月、または年) を伝える限り、このシナリオではあまり意味がないと思います。

于 2013-02-05T09:54:44.887 に答える
1

考えられるアプローチの 1 つは、何にでも一致する正規表現を作成することですが、良い一致と悪い一致を異なるグループに配置します。どのグループが失敗したかを知るために、結果に入力されているグループを調べます。

>>> regex = re.compile(r'(?:(0[1-9]|[12][0-9]|3[01])|(.{,2}))(?:(0[1-9]|1[012])|(.{,2}))(?:(19\d\d|20\d\d)|(.{,4}))')
>>> regex.match('04121987').groups()
('04', None, '12', None, '1987', None)
>>> regex.match('04721987').groups()
('04', None, None, '72', '1987', None)
>>> regex.match('0412').groups()
('04', None, '12', None, None, '')

もう 1 つの方法は、適切な有効な文字列をベースとして取り、それを入力文字列に 1 文字ずつ置き換えて、反復ごとに検証することです。ここではdatetime.datetime.strptime、検証に使用します。正規表現も使用できますが、2999 年までの年を受け入れる必要があるため、問題のものは機能しません。

from datetime import datetime

def str_to_date(s):
    good_date = '01011999'
    for i in xrange(len(good_date)):
        try:
            d = datetime.strptime(s[:i+1] + good_date[i+1:], '%d%m%Y')
        except ValueError:
            raise ValueError("Bad character '%s' at index %d" % (s[i:i+1], i))
    return d
于 2013-02-05T10:06:24.463 に答える
0

私にとって最も明白な答えは、有限オートマトンを使用するか、独自の正規表現ライブラリを作成することです。いくつかの変更を加えることで、失敗した場所を正確に特定できます。しかし、それはあなたが喜んでやろうとしていることではないと思います。

それ以外の場合は、入力が正確なサイズ、正確な日付形式になることがわかっている場合は、それを 3 つのセクター (dd mm yyyy) に分割し、すべての文字に個別に正規表現を適用してみてください。あまり良い解決策ではありませんが、必要なものが得られます。

于 2013-02-05T09:47:46.313 に答える