Programing

유효한 날짜와 일치하는 정규식

crosscheck 2020. 11. 29. 09:55
반응형

유효한 날짜와 일치하는 정규식


날짜를 확인하는 정규식을 작성하려고합니다. 정규식은 다음과 일치해야합니다.

  • M / D / YYYY
  • MM / DD / 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}

그런 다음 더 높은 수준의 언어로 범위를 확인합니다.


윤년을 포함한 모든 유효한 날짜와 일치하는 정규식은 다음과 같습니다. 허용되는 형식 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})$

의례 Asiq Ahamed


이 질문의 제목이 광범위하고 특정 날짜 형식 (예 : 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/19와 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 년 2 월 29 일 | 2012-04-30 | 2019/09/31

불일치

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

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

그것을 시도해보십시오, 그것은 매우 잘 작동하고 많은 버그로부터 코드를 방지합니다!

참고 : SQL datetime에 대한 변형을 만들었습니다. 거기에서 찾을 수 있습니다 (내 이름 찾기) : 정규식을 사용하여 타임 스탬프를 확인합니다.

피드백을 환영합니다 :)


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


Perl 확장 버전

/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;
        }
    }

이 정규식은 일치하는 구분 기호를 사용하여 01-01-2000에서 12-31-2099 사이의 날짜를 확인합니다.

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

Regex was not meant to validate number ranges(this number must be from 1 to 5 when the number preceding it happens to be a 2 and the number preceding that happens to be below 6). Just look for the pattern of placement of numbers in regex. If you need to validate is qualities of a date, put it in a date object js/c#/vb, and interogate the numbers there.


I know this does not answer your question, but why don't you use a date handling routine to check if it's a valid date? Even if you modify the regexp with a negative lookahead assertion like (?!31/0?2) (ie, do not match 31/2 or 31/02) you'll still have the problem of accepting 29 02 on non leap years and about a single separator date format.

The problem is not easy if you want to really validate a date, check this forum thread.

For an example or a better way, in C#, check this link

If you are using another platform/language, let us know


Perl 6 version

rx{
  ^

  $<month> = (\d ** 1..2)
  { $<month> <= 12 or fail }

  '/'

  $<day> = (\d ** 1..2)
  {
    given( +$<month> ){
      when 1|3|5|7|8|10|12 {
        $<day> <= 31 or fail
      }
      when 4|6|9|11 {
        $<day> <= 30 or fail
      }
      when 2 {
        $<day> <= 29 or fail
      }
      default { fail }
    }
  }

  '/'

  $<year> = (\d ** 4)

  $
}

After you use this to check the input the values are available in $/ or individually as $<month>, $<day>, $<year>. ( those are just syntax for accessing values in $/ )

No attempt has been made to check the year, or that it doesn't match the 29th of Feburary on non leap years.


If you're going to insist on doing this with a regular expression, I'd recommend something like:

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

This might make it possible to read and understand.


A slightly different approach that may or may not be useful for you.

I'm in php.

The project this relates to will never have a date prior to the 1st of January 2008. So, I take the 'date' inputed and use strtotime(). If the answer is >= 1199167200 then I have a date that is useful to me. If something that doesn't look like a date is entered -1 is returned. If null is entered it does return today's date number so you do need a check for a non-null entry first.

Works for my situation, perhaps yours too?

참고URL : https://stackoverflow.com/questions/51224/regular-expression-to-match-valid-dates

반응형