8

私と同じような質問に答えられていることは知っていますが、それらを読んだ後でも、私が探している解決策はありません。

Python 3.2.2を使用して、「月、日、年」を文字列と一致させる必要があります。うるう年の2月は30、31、または28を超えない2桁の日、2月は29です。(基本的には実際の有効な日付)

これは私がこれまでに持っているものです:

pattern = "(January|February|March|April|May|June|July|August|September|October|November|December)[,][ ](0[1-9]|[12][0-9]|3[01])[,][ ]((19|20)[0-9][0-9])"
expression = re.compile(pattern)
matches = expression.findall(sampleTextFile)

私はまだ正規表現の構文に精通していないので、不要な文字が含まれている可能性があります(コンマとスペースの[、] []は間違った方法のように感じます)が、「サンプルテキストファイルの「1991年1月26日」では、「一致」の項目の出力は(「1月」、「26」、「1991」、「19」)です。

余分な「19」が最後に表示されるのはなぜですか?

また、日付を適切に検証できるようにするために、正規表現に追加または変更できるものは何ですか?私の現在の計画は、ほぼすべての日付を受け入れ、後で、日グループを月および年のグループと比較して、日が31、30、29、28未満であるかどうかを確認することにより、高レベルの構成を使用してそれらを取り除くことです。

正規表現をどのように設計するかについての建設的な批判を含め、どんな助けでも大歓迎です。

4

6 に答える 6

6

希望する形式の任意の日付に一致する正規表現を作成する1つの方法を次に示します(ただし、コンマがオプションかどうかを微調整したり、月の省略形を追加したりすることもできます)。

years = r'((?:19|20)\d\d)'
pattern = r'(%%s) +(%%s), *%s' % years

thirties = pattern % (
     "September|April|June|November",
     r'0?[1-9]|[12]\d|30')

thirtyones = pattern % (
     "January|March|May|July|August|October|December",
     r'0?[1-9]|[12]\d|3[01]')

fours = '(?:%s)' % '|'.join('%02d' % x for x in range(4, 100, 4))

feb = r'(February) +(?:%s|%s)' % (
     r'(?:(0?[1-9]|1\d|2[0-8])), *%s' % years, # 1-28 any year
     r'(?:(29), *((?:(?:19|20)%s)|2000))' % fours)  # 29 leap years only

result = '|'.join('(?:%s)' % x for x in (thirties, thirtyones, feb))
r = re.compile(result)
print result

次に、次のようになります。

>>> r.match('January 30, 2001') is not None
True
>>> r.match('January 31, 2001') is not None
True
>>> r.match('January 32, 2001') is not None
False
>>> r.match('February 32, 2001') is not None
False
>>> r.match('February 29, 2001') is not None
False
>>> r.match('February 28, 2001') is not None
True
>>> r.match('February 29, 2000') is not None
True
>>> r.match('April 30, 1908') is not None
True
>>> r.match('April 31, 1908') is not None
False

そして、この輝かしい正規表現は何ですか、あなたは尋ねるかもしれませんか?

>>> print result
(?:(September|April|June|November) +(0?[1-9]|[12]\d|30), *((?:19|20)\d\d))|(?:(January|March|May|July|August|October|December) +(0?[1-9]|[12]\d|3[01]), *((?:19|20)\d\d))|(?:February +(?:(?:(0?[1-9]|1\d|2[0-8]), *((?:19|20)\d\d))|(?:(29), *((?:(?:19|20)(?:04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96))|2000))))

(私は当初、可能な日付を簡単に列挙するつもりでしたが、とにかく、4の倍数を除いて、基本的にその全体を手書きすることになりました。)

于 2012-04-25T04:46:07.347 に答える
2

グループは括弧で識別され(...)、左から右に、最も外側から数えられます。最終的な表現は次のようになります。

((19 | 20)[0-9] [0-9])

最も外側の括弧は年全体に一致し、内側の括弧は最初の2桁に一致します。したがって、「1989」のような日付の場合、2つの一致グループは1989と19になります。内側のグループ(最初の2桁)は必要ないため、代わりに非キャプチャグループを使用する必要があります。非キャプチャグループは、で始まり?:、次のように使用されます。(?:a|b|c)

ちなみに、ここには正規表現の使用方法に関する優れたドキュメントがいくつかあります。

于 2012-04-25T03:52:30.307 に答える
2

ここにいくつかの簡単な考えがあります:

正規表現以外のものを使用することを提案している人は皆、あなたに非常に良いアドバイスを与えています。一方、正規表現の構文について学ぶのは常に良い時期です...

角括弧内の式---角括弧内の[...]任意の1文字に一致します。したがって[,]、1文字のみを含むを書くことは、単純な装飾されていないコンマを書くこととまったく同じです,

この.findallメソッドは、文字列内の一致するすべてのグループのリストを返します。グループは括弧で識別されます---(...)そしてそれらは左から右へ、最も外側から数えます。最終的な表現は次のようになります。

((19|20)[0-9][0-9])

最も外側の括弧は年全体に一致し、内側の括弧は最初の2桁に一致します。したがって、「1989」のような日付の場合、最後の2つのマッチグループはとになり1989ます19

于 2012-04-25T03:41:53.433 に答える
1

次の正規表現があります。

pattern = "(January|February|March|April|May|June|July|August|September|October|November|December)[,][ ](0[1-9]|[12][0-9]|3[01])[,][ ]((19|20)[0-9][0-9])"

正規表現の特徴の1つは、「文字クラス」です。角かっこで囲まれた文字は、文字クラスを構成します。したがって[,]、は単一の文字,(コンマ)に一致する文字クラスです。カンマを入れた方がいいでしょう。

おそらく、コンマをオプションにしたいですか?あなたはそれの後に疑問符を置くことによってそれをすることができます: ,?

かっこで囲んだものはすべて「マッチグループ」になります。不思議なエクストラ「19」は、あなたが持っているつもりではなかったマッチグループから来たと思います。次の構文を使用して、一致しないグループを作成できます。(?:

したがって、たとえば:

r'(?:red|blue) socks'

これは「赤い靴下」または「青い靴下」と一致しますが、一致グループにはなりません。次に、それを普通の括弧の中に入れると:

r'((?:red|blue) socks)'

それはマッチグループを作り、その値は"red socks"または"blue socks"

これらのコメントを正規表現に適用すればうまくいくと思います。今はほとんど正しいです。

月に対して日付を検証することに関しては、それは正規表現の範囲をはるかに超えています。あなたのパターンは一致"February 31"し、それを修正する簡単な方法はありません。

于 2012-04-25T03:57:05.363 に答える
1

timePythonには、モジュールの一部として日付パーサーがあります。

import time
time.strptime("December 31, 2012", "%B %d, %Y")

日付形式が常に同じである場合に必要なのは、上記のすべてです。

したがって、実際の製品コードでは、日付を解析する正規表現を記述し、正規表現の結果を使用して、常に同じ形式の日付文字列を作成します。

コメントで、これは宿題だとおっしゃっていたので、正規表現のヒントを含む別の回答を投稿します。

于 2012-04-25T03:41:13.393 に答える
0

まず第一に、言ったように、私は正規表現がこの問題を解決するための最良の選択ではないと思いますが、あなたの質問に答えます。括弧を使用すると、文字列をいくつかのサブグループに分割し、関数findallを呼び出すと、作成したすべての一致するグループと一致する文字列を含むリストが作成されます。

((19|20)[0-9][0-9])

これがあなたの問題です。正規表現は、年が19または20で始まるかどうかに応じて、年間と19または20の両方に一致します。

于 2012-04-25T03:56:55.057 に答える