ISO 8601 날짜 검증시 순수한 정규 표현식을 이길


12

에서 RX에 의해 유효성을 확인 ISO 8601 , 도전은 만 표준 정규 표현식을 사용하는 것이었다 표준 날짜 형식의 유효성을 검사 하고 (전자는 RX에 대한 일반적인 작업이며, 후자는 예외적이었다). 당첨 된 답변은 778 바이트를 사용했습니다. 이 도전은 당신이 선택한 언어를 사용하지만 특별한 날짜 함수 나 클래스를 사용하지 않고 이길 수 있습니다 .

도전

가장 짧은 코드 찾기

  1. Proleptic Gregorian 달력 에서 가능한 모든 날짜의 유효성을 검사합니다 (1582 년에 처음 채택되기 전의 모든 날짜에도 적용됨).
  2. 유효하지 않은 날짜와 일치하지 않습니다
  3. 날짜 및 시간을 처리하기 위해 사전 정의 된 함수, 메소드, 클래스, 모듈 또는 이와 유사한 것을 사용하지 않습니다. 즉 문자열 및 숫자 연산에 의존합니다.

산출

결과는 진실되거나 거짓입니다. 날짜를 출력하거나 변환 할 필요는 없습니다.

입력

입력은 3 가지 확장 된 ISO 8601 날짜 형식으로 된 단일 문자열입니다 .

처음 두 가지는 ±YYYY-MM-DD(년, 월, 일)과 ±YYYY-DDD(년, 일)입니다. 둘 다 도약의 날을 위해 특별한 케이스가 필요합니다. 이 확장 RX와는 별도로 순진하게 일치합니다.

(?<year>[+-]?\d{4,})-(?<month>\d\d)-(?<day>\d\d)
(?<year>[+-]?\d{4,})-(?<doy>\d{3})

세 번째 입력 형식은 ±YYYY-wWW-D(년, 주, 일)입니다. 복잡한 도약 주간 패턴으로 인해 복잡한 것입니다.

(?<year>[+-]?\d{4,})-W(?<week>\d\d)-(?<dow>\d)

정황

윤년 예 기적 그레고리 안 달력에는 포함 윤일 …-02-29 따라서 그것은 따라서 366 일 긴하다 …-366존재한다. 이것은 400으로 나눌 수 없다면 서수는 4로 나눌 수 있지만 100으로 나눌 수없는 연도 에서 발생합니다.이 달력에는 0 년이 존재하며 윤년입니다.

ISO 주 달력 의 긴 연도 에는 53 주가 포함되며 …-W53-…, 이는“ 윤리 주 ” 라고 할 수 있습니다. 이것은 1 월 1 일이 목요일 인 모든 해와 수요일이되는 모든 윤년에 발생합니다. 0001-01-01그리고 2001-01-01월요일입니다. 일반적으로 5-6 년마다 불규칙적으로 보이는 것처럼 보입니다.

1 년은 최소 4 자리입니다. 10 자리가 넘는 연도는 우주의 나이 (약 140 억 년)에 가깝기 때문에 지원할 필요가 없습니다. 실제 더하기 기호는 4 자리가 넘는 연도를 요구하지만, 더하기 부호는 선택 사항입니다.

일부 또는 잘린 날짜 (예 : 일 정밀도 미만)는 허용되지 않아야합니다. -모든 경우에 하이픈을 구분해야합니다. (이러한 전제 조건으로 인해 +항상 선택 사항이 될 수 있습니다.)

규칙

이것은 코드 골프입니다. 바이트 단위의 가장 짧은 코드가 이깁니다. 조기 답변이 동점입니다.

테스트 사례

유효한 테스트

2015-08-10
2015-10-08
12015-08-10
-2015-08-10
+2015-08-10
0015-08-10
1582-10-10
2015-02-28
2016-02-29
2000-02-29
0000-02-29
-2000-02-29
-2016-02-29
+2016-02-29
200000-02-29
-200000-02-29
+200000-02-29
2016-366
2000-366
0000-366
-2000-366
-2016-366
+2016-366
2015-081
2015-W33-1
2015-W53-7
+2015-W53-7
+2015-W33-1
-2015-W33-1
 2015-08-10 

마지막 것은 선택적으로 유효합니다. 즉, 입력 문자열의 선행 및 후행 공백이 잘릴 수 있습니다.

잘못된 형식

-0000-08-10     # that's an arbitrary decision
15-08-10        # year is at least 4 digits long
2015-8-10       # month (and day) is exactly two digits long, i.e. leading zero is required
015-08-10       # year is at least 4 digits long
20150810        # though a valid ISO format, we require separators; could also be interpreted as a 8-digit year
2015 08 10      # separator must be hyphen-minus
2015.08.10      # separator must be hyphen-minus
2015–08–10      # separator must be hyphen-minus
2015-0810
201508-10       # could be October in the year 201508
2015 - 08 - 10  # no internal spaces allowed
2015-w33-1      # letter ‘W’ must be uppercase
2015W33-1       # it would be unambiguous to omit the separator in front of a letter, but not in the standard
2015W331        # though a valid ISO format we require separators
2015-W331
2015-W33        # a valid ISO date, but we require day-precision
2015W33         # though a valid ISO format we require separators and day-precision
2015-08         # a valid ISO format, but we require day-precision
201508          # a valid but ambiguous ISO format
2015            # a valid ISO format, but we require day-precision

유효하지 않은 날짜

2015-00-10  # month range is 1–12
2015-13-10  # month range is 1–12
2015-08-00  # day range is 1–28 through 31
2015-08-32  # max. day range is 1–31
2015-04-31  # day range for April is 1–30
2015-02-30  # day range for February is 1–28 or 29
2015-02-29  # day range for common February is 1–28
2100-02-29  # most century years are non-leap
-2100-02-29 # most century years are non-leap
2015-000    # day range is 1–365 or 366
2015-366    # day range is 1–365 in common years
2016-367    # day range is 1–366 in leap years
2100-366    # most century years are non-leap
-2100-366   # most century years are non-leap
2015-W00-1  # week range is 1–52 or 53
2015-W54-1  # week range is 1–53 in long years
2016-W53-1  # week range is 1–52 in short years
2015-W33-0  # day range is 1–7
2015-W33-8  # day range is 1–7

2
주제와,하지만 어쩌면 유용한 - 스택 오버플로는 : stackoverflow.com/questions/28020805/...는 (나는 그것을 게시하지해야하는지 말해)
다니엘 D

프로그래머가 YEC (Young-Earth Creationist)라면?
Leaky Nun

-0000-08-10exaclty이 임의의 결정 무엇인가? 연도를 0으로 허용하지 않습니까?
edc65

@ edc65 예 +0000-08-10와는 0000-08-10대신 사용해야합니다. 참고하지만,이 도전의 정규 표현식 변형의 허용 대답은 (즉, 그래서 실패한 상태가 정말 아니다,이 특정 테스트 케이스를 실패 해야 아닌 필수 ).
Crissov

@KennyLau 그러면 프로그래머 가 틀렸다 .
Arcturus

답변:


2

자바 스크립트 (ES6), 236

음수 0 년 ( -0000)을 허용하는 236 바이트 참 또는 거짓을 반환

s=>!!([,y,w,d]=s.match(/^([+-]?\d{4,})(-W?\d\d)?(-\d{1,3})$/)||[],n=y%100==0&y%400!=0|y%4!=0,l=((l=y-1)+8-~(l/4)+~(l/100)-~(l/400))%7,l=l==5|l==4&!n,+d&&(-w?d>`0${2+n}0101001010`[~w]-32:w?(w=w.slice(2),w>0&w<(53+l)&d>-8):d[3]&&d>n-367))

부정적인 영 컷 2 바이트를 검사를 추가하지만은 자바 스크립트 수치가 13 주 추가 -0존재를, 그리고 0으로 동일하게 특례하지만 1/-0입니다 -Infinity. 이 버전은 0 또는 1을 반환합니다

s=>([,y,w,d]=s.match(/^([+-]?\d{4,})(-W?\d\d)?(-\d{1,3})$/)||[],n=y%100==0&y%400!=0|y%4!=0,l=((l=y-1)+8-~(l/4)+~(l/100)-~(l/400))%7,l=l==5|l==4&!n,+d&&(-w?d>`0${2+n}0101001010`[~w]-32:w?(w=w.slice(2),w>0&w<(53+l)&d>-8):d[3]&&d>n-367))&!(!+y&1/y<0)

테스트

Check=
  s=>!! // to obtain a true/false 
  (
    // parse year in y, middle part in w, day in d
    // day will be negative with 1 or 3 numeric digits and could be 0
    // week will be '-W' + 2 digits
    // month will be negative with2 digits and could be 0
    // if the date is in format yyyy-ddd, then w is empty
    [,y,w,d] = s.match(/^([+-]?\d{4,})(-W?\d\d)?(-\d{1,3})$/) || [],
    n = y%100==0 & y%400!=0 | y%4!=0, // n: not leap year
    l = ((l=y-1) + 8 -~(l/4) +~(l/100) -~(l/400)) % 7, 
    l = l==5| l==4 & !n, // l: long year (see http://mathforum.org/library/drmath/view/55837.html)
    +d && ( // if d is not empty and not 0
     -w // if w is numeric and not 0, then it's the month (negative)
     ? d > `0${2+n}0101001010`[~w] - 32 // check month length (for leap year too)
      : w // if w is not empty, then it's the week ('-Wnn')
        ? ( w = w.slice(2), w > 0 & w < (53+l) & d >- 8) // check long year too
        : d[3] && d > n-367 // else d is the prog day, has to be 3 digits and < 367 o 366
    )
  )

console.log=x=>O.textContent += x +'\n'

OK=['1900-01-01','2015-08-10','2015-10-08','12015-08-10','-2015-08-10','+2015-08-10'
,'0015-08-10','1582-10-10','2015-02-28','2016-02-29','2000-02-29'
,'0000-02-29','-2000-02-29','-2016-02-29','+2016-02-29','200000-02-29'
,'-200000-02-29','+200000-02-29','2016-366','2000-366','0000-366'
,'-2000-366','-2016-366','+2016-366','2015-081','2015-W33-1'
,'2015-W53-7','+2015-W53-7','+2015-W33-1','-2015-W33-1','2015-08-10']

KO=['-0000-08-10','15-08-10','2015-8-10','015-08-10','20150810','2015 08 10'
,'2015.08.10','2015–08–10','2015-0810','201508-10','2015 - 08 - 10','2015-w33-1'
,'2015W33-1','2015W331','2015-W331','2015-W33','2015W33','2015-08','201508'
,'2015','2015-00-10','2015-13-10','2015-08-00','2015-08-32','2015-04-31'
,'2015-02-30','2015-02-29','2100-02-29','-2100-02-29','2015-000'
,'2015-366','2016-367','2100-366','-2100-366','2015-W00-1'
,'2015-W54-1','2016-W53-1','2015-W33-0','2015-W33-8']

console.log('Valid')
OK.forEach(x=>console.log(Check(x)+' '+x))
console.log('Not valid')
KO.forEach(x=>console.log(Check(x)+' '+x))
<pre id=O></pre>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.