문제

날짜의 유효성을 검사하는 정규식을 작성하려고 합니다.정규식은 다음과 일치해야 합니다.

  • 월/일/YYYY
  • 월/일/년
  • 한 자리 월은 앞에 0으로 시작될 수 있습니다(예:2008년 3월 12일)
  • 한 자리 날짜는 앞에 0으로 시작될 수 있습니다(예:2008년 3월 2일)
  • 2월 30일이나 2월 31일은 포함할 수 없습니다(예:2008년 2월 31일)

지금까지 나는

^(([1-9]|1[012])[-/.]([1-9]|[12][0-9]|3[01])[-/.](19|20)\d\d)|((1[012]|0[1-9])(3[01]|2\d|1\d|0[1-9])(19|20)\d\d)|((1[012]|0[1-9])[-/.](3[01]|2\d|1\d|0[1-9])[-/.](19|20)\d\d)$

이는 여전히 2008년 2월 30일 및 2008년 2월 31일을 포함하는 것을 제외하고는 올바르게 일치합니다.

더 나은 제안이 있는 사람이 있나요?

편집하다: 나는 찾았다 대답 RegExLib에서

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

MM/DD/YYYY 형식을 따르는 모든 유효한 월과 일치합니다.

도움을 주신 모든 분들께 감사드립니다.

도움이 되었습니까?

해결책

이는 정규식을 적절하게 사용하지 않는 것입니다.사용하시면 더 좋을 것 같아요

[0-9]{2}/[0-9]{2}/[0-9]{4}

그런 다음 고급 언어로 범위를 확인합니다.

다른 팁

윤년을 포함하여 모든 유효한 날짜와 일치하는 Reg ex는 다음과 같습니다.허용되는 형식 mm/dd/yyyy, mm-dd-yyyy 또는 mm.dd.yyyy 형식

^(?:(?:(?:0?[13578]|1[02])(\/|-|\.)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/|-|\.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:0?2(\/|-|\.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/|-|\.)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

예의 아시크 아하메드

이 질문의 제목이 광범위하고 특정 날짜 형식(예: OP)과 일치시키는 데 사용할 수 있는 정규식을 찾고 있었기 때문에 여기에 왔습니다.그러나 많은 답변과 의견이 포괄적으로 강조되었듯이 품질이 좋지 않거나 구조화되지 않은 소스 데이터와 혼합된 날짜를 추출할 때 효과적인 패턴을 구성하는 것을 매우 까다롭게 만드는 함정이 많다는 것을 발견했습니다.

문제를 조사하면서 구분 기호와 일치하는 4개의 간단한 하위 표현식과 연도, 월, 일 필드의 유효한 범위를 순서대로 배열하여 정규 표현식을 구축할 수 있는 시스템을 생각해냈습니다. 당신은 요구합니다.

이것들은 :-

구분 기호

[^\w\d\r\n:] 

이는 단어 문자, 숫자 문자, 캐리지 리턴, 새 줄 또는 콜론이 아닌 모든 항목과 일치합니다.날짜처럼 보이는 시간에 일치하는 것을 방지하려면 콜론이 있어야 합니다(내 테스트 데이터 참조).

패턴의 이 부분을 최적화하여 일치 속도를 높일 수 있지만 이는 대부분의 유효한 구분 기호를 감지하는 좋은 기반입니다.

그러나 참고하십시오.실제로는 유효한 날짜가 아닐 수 있는 2/12-73과 같은 혼합 구분 기호가 있는 문자열과 일치합니다.

연도 값

(\d{4}|\d{2})

이는 2자리 또는 4자리 그룹과 일치하며 대부분의 경우 허용되지만 0-999년 또는 9999년 이후의 데이터를 처리하는 경우 대부분의 경우 1, 3이므로 처리 방법을 결정해야 합니다. 또는 >4자리 연도는 쓰레기입니다.

월 값

(0?[1-9]|1[0-2])

앞에 0이 있거나 없거나 1에서 12 사이의 숫자와 일치합니다. 참고:0과 00이 일치하지 않습니다.

날짜 값

(0?[1-9]|[12]\d|30|31)

앞에 0이 있거나 없거나 1에서 31 사이의 숫자와 일치합니다. 참고:0과 00이 일치하지 않습니다.

이 표현식은 날짜, 월, 연도 형식의 날짜와 일치합니다.

(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})

그러나 일부 연도, 월 날짜 항목과도 ​​일치합니다.또한 전체 날짜 문자열이 선택되었는지 확인하고 형식이 올바르지 않은 데이터에서 유효한 하위 날짜가 추출되는 것을 방지하기 위해 경계 연산자를 사용하여 예약해야 합니다.경계 태그가 없으면 20/12/194는 20/12/19와 일치하고 101/12/1974는 01/12/1974와 일치합니다.

다음 표현식의 결과를 위의 표현식과 넌센스 섹션(아래)의 테스트 데이터와 비교하세요.

\b(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})\b

이 정규식에는 유효성 검사가 없으므로 형식은 확실하지만 2001년 2월 31일과 같이 유효하지 않은 날짜가 일치됩니다.이는 데이터 품질 문제이며 다른 사람들이 말했듯이 정규식은 데이터의 유효성을 검사할 필요가 없습니다.

개발자로서 귀하는 코드에서 추가 유효성 검사를 수행하고 처리해야 하는 소스 데이터의 품질을 보장할 수 없기 때문에 일치시키려고 하면 그리고 RegEx의 데이터를 검증하면 매우 지저분해지고 지원하지 않으면 지원하기가 어려워집니다. 매우 간결한 문서.

쓰레기는 들어가고 쓰레기는 나옵니다.

즉, 날짜 값이 다양한 혼합 형식이 있고 가능한 한 많이 추출해야 하는 경우;다음과 같이 몇 가지 표현식을 결합할 수 있습니다.

이 (비참한) 표현식은 DMY 및 YMD 날짜와 일치합니다.

(\b(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})\b)|(\b(0?[1-9]|1[0-2])[^\w\d\r\n:](0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](\d{4}|\d{2})\b)

그러나 1973년 6월 9일과 같은 날짜가 9월 6일인지 6월 9일인지 알 수 없습니다.나는 그것이 어딘가에서 문제를 일으키지 않을 시나리오를 생각하는 데 어려움을 겪고 있습니다. 그것은 나쁜 습관이며 그렇게 처리할 필요가 없습니다. 데이터 소유자를 찾아 거버넌스 망치로 때리십시오. .

마지막으로 구분 기호 없이 YYYYMMDD 문자열을 일치시키려는 경우 불확실성을 일부 제거할 수 있으며 표현식은 다음과 같습니다.

\b(\d{4})(0[1-9]|1[0-2])(0[1-9]|[12]\d|30|31)\b

하지만 다시 한번 말씀드리지만, 20010231(2월 31일!)과 같이 형식은 좋지만 유효하지 않은 값과 일치합니다. :)

테스트 데이터

이 스레드의 솔루션을 실험하면서 다양한 유효한 날짜와 유효하지 않은 날짜 및 일치를 원할 수도 있고 원하지 않을 수도 있는 몇 가지 까다로운 상황(예:여러 줄의 날짜 및 날짜와 일치할 수 있는 시간입니다.

이것이 누군가에게 유용하기를 바랍니다.

Valid Dates in various formats

Day, month, year
2/11/73
02/11/1973
2/1/73
02/01/73
31/1/1973
02/1/1973
31.1.2011
31-1-2001
29/2/1973
29/02/1976 
03/06/2010
12/6/90

month, day, year
02/24/1975 
06/19/66 
03.31.1991
2.29.2003
02-29-55
03-13-55
03-13-1955
12\24\1974
12\30\1974
1\31\1974
03/31/2001
01/21/2001
12/13/2001

Match both DMY and MDY
12/12/1978
6/6/78
06/6/1978
6/06/1978

using whitespace as a delimiter

13 11 2001
11 13 2001
11 13 01 
13 11 01
1 1 01
1 1 2001

Year Month Day order
76/02/02
1976/02/29
1976/2/13
76/09/31

YYYYMMDD sortable format
19741213
19750101

Valid dates before Epoch
12/1/10
12/01/660
12/01/00
12/01/0000

Valid date after 2038

01/01/2039
01/01/39

Valid date beyond the year 9999

01/01/10000

Dates with leading or trailing characters

12/31/21/
31/12/1921AD
31/12/1921.10:55
12/10/2016  8:26:00.39
wfuwdf12/11/74iuhwf
fwefew13/11/1974
01/12/1974vdwdfwe
01/01/99werwer
12321301/01/99

Times that look like dates

12:13:56
13:12:01
1:12:01PM
1:12:01 AM

Dates that runs across two lines

1/12/19
74

01/12/19
74/13/1946

31/12/20
08:13

Invalid, corrupted or nonsense dates

0/1/2001
1/0/2001
00/01/2100
01/0/2001
0101/2001
01/131/2001
31/31/2001
101/12/1974
56/56/56
00/00/0000
0/0/1999
12/01/0
12/10/-100
74/2/29
12/32/45
20/12/194

2/12-73

유지 관리 가능한 Perl 5.10 버전

/
  (?:
      (?<month> (?&mon_29)) [\/] (?<day>(?&day_29))
    | (?<month> (?&mon_30)) [\/] (?<day>(?&day_30))
    | (?<month> (?&mon_31)) [\/] (?<day>(?&day_31))
  )
  [\/]
  (?<year> [0-9]{4})

  (?(DEFINE)
    (?<mon_29> 0?2 )
    (?<mon_30> 0?[469]   | (11) )
    (?<mon_31> 0?[13578] | 1[02] )

    (?<day_29> 0?[1-9] | [1-2]?[0-9] )
    (?<day_30> 0?[1-9] | [1-2]?[0-9] | 30 )
    (?<day_31> 0?[1-9] | [1-2]?[0-9] | 3[01] )
  )
/x

이 버전에서는 이름으로 요소를 검색할 수 있습니다.

say "Month=$+{month} Day=$+{day} Year=$+{year}";

(연도 값을 제한하려는 시도는 없었습니다.)

다음 형식으로 날짜 유효성을 제어하려면 다음을 수행하십시오.

YYYY/MM/DD 또는 YYYY-MM-DD

다음 정규식을 사용하는 것이 좋습니다.

(((19|20)([2468][048]|[13579][26]|0[48])|2000)[/-]02[/-]29|((19|20)[0-9]{2}[/-](0[4678]|1[02])[/-](0[1-9]|[12][0-9]|30)|(19|20)[0-9]{2}[/-](0[1359]|11)[/-](0[1-9]|[12][0-9]|3[01])|(19|20)[0-9]{2}[/-]02[/-](0[1-9]|1[0-9]|2[0-8])))

성냥

2016-02-29 | 2012-04-30 | 2019/09/31

일치하지 않는 항목

2016-02-30 | 2012-04-31 | 2019/09/35

'/' 또는 '-' 구분 기호만 허용하려는 경우 맞춤설정할 수 있습니다.이 RegEx는 날짜의 유효성을 엄격하게 제어하고 28, 30 및 31일 월을 확인하며 윤년도 29/02 월로 확인합니다.

시도해 보세요. 매우 잘 작동하고 코드에 많은 버그가 발생하는 것을 방지할 수 있습니다!

참고:SQL 날짜/시간에 대한 변형을 만들었습니다.거기에서 찾을 수 있습니다(내 이름을 찾으세요). 타임스탬프의 유효성을 검사하는 정규식

피드백을 환영합니다 :)

이 목적을 위해 정규식을 과도하게 확장하는 것 같습니다.내가 할 일은 정규식을 사용하여 몇 가지 날짜 형식을 일치시킨 다음 별도의 함수를 사용하여 추출된 날짜 필드의 값을 검증하는 것입니다.

펄 확장 버전

참고 사용 /x 수정자.

/^(
      (
        ( # 31 day months
            (0[13578])
          | ([13578])
          | (1[02])
        )
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
          | (3[01])
        )
      )
    | (
        ( # 30 day months
            (0[469])
          | ([469])
          | (11)
        )
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
          | (30)
        )
      )
    | ( # 29 day month (Feb)
        (2|02)
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
        )
      )
    )
    [\/]
    # year
    \d{4}$

  | ^\d{4}$ # year only
/x

원래의

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

위의 제안이 제대로 작동하지 않으면 이것을 사용합니다. 날짜를 얻으므로 이 표현식을 50개의 링크를 통해 실행했고 각 페이지의 모든 날짜를 얻었습니다.

^20\d\d-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(0[1-9]|[1-2][0-9]|3[01])$ 
    var dtRegex = new RegExp(/[1-9\-]{4}[0-9\-]{2}[0-9\-]{2}/);
    if(dtRegex.test(date) == true){
        var evalDate = date.split('-');
        if(evalDate[0] != '0000' && evalDate[1] != '00' && evalDate[2] != '00'){
            return true;
        }
    }

이 정규식은 일치하는 구분 기호를 사용하여 2000년 1월 1일과 2099년 12월 31일 사이의 날짜를 확인합니다.

^(0[1-9]|1[012])([- /.])(0[1-9]|[12][0-9]|3[01])\2(19|20)\d\d$

Regex는 숫자 범위를 검증하기 위한 것이 아닙니다. 앞의 숫자가 2이고 그 앞의 숫자가 6 미만인 경우 이 숫자는 1에서 5 사이여야 합니다.정규식에서 숫자 배치 패턴을 찾으십시오.날짜의 품질을 확인해야 하는 경우 날짜 개체 js/c#/vb에 넣고 거기에서 숫자를 조사합니다.

이것이 귀하의 질문에 대한 답변이 아니라는 것을 알고 있지만 날짜 처리 루틴을 사용하여 유효한 날짜인지 확인하는 것은 어떻습니까?(?!31/0?2)(즉, 31/2 또는 31/02와 일치하지 않음)와 같은 부정 예측 어설션으로 정규 표현식을 수정하더라도 윤년이 아닌 해에 29 02를 허용하는 문제가 여전히 발생합니다. 단일 구분 기호 날짜 형식에 대해 설명합니다.

날짜를 실제로 확인하려면 문제가 쉽지 않습니다. 이것을 확인하십시오. 포럼 스레드.

예나 더 나은 방법을 보려면 C#에서 다음을 확인하세요. 이 링크

다른 플랫폼/언어를 사용하고 있다면 알려주십시오.

펄 6 버전

이것을 사용하여 입력을 확인한 후 값을 사용할 수 있습니다. $/ 또는 개별적으로 $<month>, $<day>, $<year>.(이것은 값에 액세스하기 위한 구문일 뿐입니다. $/ )

연도를 확인하거나 윤년이 아닌 해의 2월 29일이 일치하지 않는지 확인하려는 시도가 없었습니다.

정규식을 사용하여 이 작업을 수행하려면 다음과 같은 것을 권장합니다.

( (0?1|0?3| <...> |10|11|12) / (0?1| <...> |30|31) |
  0?2 / (0?1| <...> |28|29) ) 
/ (19|20)[0-9]{2}

이것 ~할 것 같다 읽고 이해할 수 있도록 하라.

귀하에게 유용할 수도 있고 그렇지 않을 수도 있는 약간 다른 접근 방식입니다.

나는 PHP에 있습니다.

이와 관련된 프로젝트의 날짜는 2008년 1월 1일 이전일 수 없습니다.그래서 입력된 '날짜'를 취하고 strtotime()을 사용합니다.대답이 >= 1199167200이면 나에게 유용한 날짜가 있는 것입니다.날짜처럼 보이지 않는 내용을 입력하면 -1이 반환됩니다.null이 입력되면 오늘 날짜 숫자가 반환되므로 먼저 null이 아닌 항목을 확인해야 합니다.

내 상황에도 효과가 있을 것입니다. 아마도 당신의 상황에도 효과가 있을까요?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top