2012-04-25 4 views
6

나는 대답 한 비슷한 질문이 있다는 것을 알고 있지만, 나는 그들을 통해 읽은 후에도 여전히 내가 찾고있는 해결책이 없다.Python에서 정규식과 일치하는 날짜?

파이썬 3.2.2를 사용하면 "월, 일, 년"과 일치해야합니다. 윤곽선의 달은 2 월 30 일, 31 일 또는 28 일, 윤년 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) 

그래서 난 불필요한 거기에 문자를합니다 ([있을 수 있습니다 (기본적으로 진짜와 유효 날짜)

이것은 내가 지금까지 무엇을 가지고 ,] []는 쉼표와 공백으로 잘못 생각합니다.),하지만 필자의 샘플 텍스트 파일에서 "January, 26, 1991"과 일치 시키려고하면 "matches"항목의 인쇄가 다음과 같이됩니다. ('1 월', '26', '1991', '19').

끝에 '19'가 나타나는 이유는 무엇입니까?

또한 무엇을 추가하거나 날짜의 유효성을 올바르게 확인할 수있는 정규식에서 변경할 수 있습니까? 내 계획은 지금 거의 모든 날짜를 받아들이고 날짜 그룹을 달 및 연도 그룹과 비교하여 날짜가 높은지 확인하는 것입니다. < 31,30,29,28

모두 도움이 많이 평가할 수있는 건설적인 비판을 포함하여 내 정규 표현식을 설계하는 방법에 대해 고맙겠습니다.

+5

왜 정규 표현식을 사용해야합니까? (이제 두 가지 문제가 있습니다 ...) – geoffspear

+0

나는 워록이 인용하고있는 말을 믿는다. 어떤 사람들은 문제에 직면했을 때 "나는 정규식을 사용할 것"이라고 생각한다. 이제 그들은 두 가지 문제가있다. ' 나는 동의 할 의향이있다. 문자열과 2 개의 숫자를 추출하는 것이 좋습니다. (아마도 간단하고 간단한 정규 표현식을 사용하지만 문자열을 쉼표로 분리하여 사용하는 것이 좋습니다.) 그런 다음 datetime을 사용하여 날짜가 유효한지 테스트합니다. –

+0

조언을 주셔서 감사합니다. 그러나 이것은 숙제 지정으로 날짜와 일치하는 표현식을 만들어야합니다. – ahabos

답변

6

여기에 (당신은 분명 등등, 쉼표는 선택 여부를 조정할 개월 약어를 추가 할 수 있지만) 원하는 형식의 날짜와 일치하는 정규 표현식을 만드는 하나 개의 방법 : 다음

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 

을 우리 have :

>>> 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)))) 

(나는 처음에 가능한 날짜 놀림조 열거 할 목적으로하지만, 나는 기본적으로 결국 손으로 작성 어쨌든 네의 배수를 제외한 전체 총 것.)

+0

고마워요! 나는 당신이 나에게 천천히 준 분석을 통해 개별 구성 요소를 분석하고 이해하지만, 그것을 수행하는 가장 좋은 방법은 이름을 제외하고 기본적으로 차이가없는 달을 함께 그룹화하고 2 월을 별도로 분리하는 것이었을 것입니다. 나머지 부분은 표현식의 다른 부분 인 – ahabos

+0

과 일치합니다. 나는 정규 표현식을 달에 대해 달을 확인하는 "쉬운 방법"이 없다고 말했습니다. 그래서 당신은 그것을하는 법을 보여주었습니다 ... 어려운 길 ... 당신, 선생님, 제정신이 아닙니다. 그러나 그것은 좋은 광기의 종류입니다. +1! 추신 나는 특히 윤년 검사기를 좋아합니다. – steveha

+0

패턴 = R '(%의 S) + (%의 (S)) * % S'% 저 .. 패턴 = 오류를 나타내는 년 (%의 S) + (%의 S)를, * % S '% 년 오류 : 형식 문자열에 대한 인수가 충분하지 않습니다. – monkey

1

파이썬은 time 모듈의 일부로 날짜 파서 있습니다

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

위의 날짜 형식은 항상 동일한 경우 당신이 필요로하는 모두이다.

그래서 실제 제작 코드에서는 날짜를 구문 분석하는 정규식을 작성한 다음 정규식의 결과를 사용하여 항상 동일한 형식의 날짜 문자열을 작성합니다.

당신이 코멘트에서 이것이 숙제라고 말했을 때 정규 표현식에 대한 팁을 포함한 또 다른 답변을 게시 할 것입니다. 당신에게 아주 좋은 조언을주고 당신이 정규 표현식이 아닌 다른 무언가를 사용 제안한다

모두 :

+0

숙제 인 정규 표현식을 사용해야합니다. – ahabos

+0

날짜가 문자열인데 일치하는 'regex'처럼 작동하지 않으면 날짜 객체를 만듭니다. 문자열 또는 큰 텍스트의 날짜. – Suz

2

여기에 몇 가지 빠른 생각입니다. 반면에 정규 표현식 구문에 대해 자세히 배우는 것이 좋습니다.

대괄호 안의 표현 - [...] -은 대괄호 안에있는 하나의 문자와 일치합니다. 따라서 하나의 문자 만 포함하는 [,]을 작성하면 단순한 꾸밈없는 쉼표 (예 : ,)를 쓰는 것과 완전히 동일합니다.

.findall 메서드는 문자열에서 일치하는 모든 그룹의 목록을 반환합니다. 그룹은 괄호로 묶음 ((...))으로 식별되며 왼쪽에서 오른쪽, 가장 바깥 쪽에서부터 세어 봅니다. 귀하의 최종 표현은 다음과 같습니다

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

가장 바깥 쪽 괄호

전체 년과 일치하고, 내부 괄호의 처음 두 자릿수와 일치합니다. 따라서 '1989'와 같은 날짜의 경우 최종 일치 그룹은 198919이됩니다.

+2

일치하지 않는 그룹에 대해 해결 방법을 알려주십시오. (? : 19 | 20) – ricochet1k

+0

아니, 내가 네가 해줄거야. 나는 정말로 "고칠 필요가있다"고 확신하지 못한다. 왜냐하면 아무것도 "깨진"것이 없기 때문이다. 나는 그 행동을 설명하기를 원했다. – larsks

2

그룹은 괄호 (...)에 의해 식별되며 왼쪽에서 오른쪽, 가장 바깥 쪽의 첫 번째로 계산됩니다. 귀하의 최종 표현은 다음과 같습니다

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

가장 바깥 쪽 괄호

전체 년과 일치하고, 내부 괄호의 처음 두 자릿수와 일치합니다. 따라서 "1989"와 같은 날짜의 경우 두 일치 그룹은 1989 년과 19 일이됩니다. 내부 그룹 (처음 두 자리)을 원하지 않으므로 대신 비 캡처 그룹을 사용해야합니다. 비 캡처 그룹은 다음과 같이 사용되는 ?:으로 시작합니다. (?:a|b|c)

그런데 정규 표현식 here을 사용하는 방법에 대한 좋은 설명서가 있습니다.

0

우선, 정규 표현식이이 문제를 해결하는 것이 아니라 귀하의 질문에 대답하는 최선의 선택이라고 생각합니다. 괄호를 사용하면 문자열을 여러 개의 하위 그룹으로 나누어서 findall 함수를 호출 할 때 만든 모든 일치하는 그룹과 일치하는 문자열이있는 목록을 만듭니다. 여기

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

이 문제는 정규식에 따라 전체 년 19 또는 20 모두 일치합니다 당신이 정규 표현식이 19 또는 20

+0

괄호는 균형이 맞지 않습니다. – ricochet1k

+0

고마워요. – danielz

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])" 
에게

정규 표현식의 한 기능은 "문자 클래스"입니다. 대괄호 안에있는 문자는 문자 클래스를 만듭니다. 따라서 [,]은 단일 문자 인 , (쉼표)과 일치하는 문자 클래스입니다. 콤마를 넣을 수도 있습니다.

아마 쉼표를 선택하고 싶습니까? 그 뒤에 물음표를 넣으면됩니다 : ,?

괄호 안에 넣으면 "일치 그룹"이됩니다. 신비한 "19"는 당신이 가진 것이 아닌 성냥 그룹에서 나온 것 같습니다. 예를 들어 (?:

그래서, : :이 구문을 사용하여 일치하지 않는 그룹을 만들 수 있습니다

r'(?:red|blue) socks' 

이 "빨간 양말"또는 "파란 양말"을 일치합니다하지만 일치하는 그룹을하지 않습니다. 그런 다음 일반 괄호 안에 있음을 넣어 경우 값이 일치하는 그룹을 만들 것

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

"red socks" 또는 "blue socks"

당신이 정규 표현식에 이러한 의견을 적용 할 경우 내 생각 일 것, 그것은 작동합니다. 지금은 대체로 정확합니다.

달에 대한 유효성 검사는 정규 표현식의 범위를 벗어납니다. 귀하의 패턴은 "February 31"과 일치하며 쉽게 수정할 수 없습니다.

관련 문제