Đánh bại các biểu thức chính quy thuần túy khi xác thực các ngày ISO 8601


12

Trong ValiDate ISO 8601 của RX , thách thức là chỉ sử dụng các biểu thức chính quy tiêu chuẩn để xác thực các định dạng giá trị ngày tiêu chuẩn (trước đây là công việc chung cho RX, sau này là bất thường). Câu trả lời chiến thắng đã sử dụng 778 byte. Thách thức này là đánh bại việc sử dụng bất kỳ ngôn ngữ nào bạn chọn, nhưng không có các chức năng hoặc lớp ngày đặc biệt .

Thử thách

Tìm mã ngắn nhất mà

  1. xác nhận mọi ngày có thể trong lịch Proleptic Gregorian (cũng áp dụng cho tất cả các ngày trước khi áp dụng lần đầu tiên vào năm 1582),
  2. không khớp với bất kỳ ngày không hợp lệ nào và
  3. không sử dụng bất kỳ hàm, phương thức, lớp, mô-đun được xác định trước nào để xử lý ngày (và thời gian), tức là dựa vào các hoạt động chuỗi và số.

Đầu ra

Đầu ra là trung thực hoặc falsey. Không cần thiết phải xuất hoặc chuyển đổi ngày.

Đầu vào

Đầu vào là một chuỗi trong bất kỳ 3 định dạng ngày ISO 8601 mở rộng - không có lần.

Hai cái đầu tiên là ±YYYY-MM-DD(năm, tháng, ngày) và ±YYYY-DDD(năm, ngày). Cả hai đều cần vỏ đặc biệt cho ngày nhuận. Chúng được kết hợp một cách ngây thơ bởi các RX mở rộng này:

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

Định dạng đầu vào thứ ba là ±YYYY-wWW-D(năm, tuần, ngày). Đây là một trong những phức tạp vì mô hình tuần nhuận phức tạp.

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

Điều kiện

Một năm nhuận trong lịch Gregorian Proleptic chứa ngày nhuận …-02-29 và do đó nó dài 365 ngày, do đó …-366tồn tại. Điều này xảy ra trong bất kỳ năm nào có số thứ tự (có thể âm) chia hết cho 4, nhưng không bằng 100 trừ khi nó chia hết cho 400. Năm không tồn tại trong lịch này và đó là năm nhuận.

Một năm dài trong lịch tuần ISO có tuần thứ 53 …-W53-…, trong đó người ta có thể gọi là tuần nhuận nhuận . Điều này xảy ra trong tất cả các năm trong đó ngày 1 tháng 1 là thứ năm và thêm vào đó là tất cả các năm nhuận trong đó là thứ tư. 0001-01-012001-01-01là thứ Hai. Nó thường xảy ra cứ sau 5 hoặc 6 năm, theo một mô hình dường như không đều.

Một năm có ít nhất 4 chữ số. Những năm có hơn 10 chữ số không cần phải được hỗ trợ, vì nó đủ gần với tuổi của vũ trụ (khoảng 14 tỷ năm). Dấu cộng hàng đầu là tùy chọn, mặc dù tiêu chuẩn thực tế cho thấy nó cần được yêu cầu trong nhiều năm với hơn 4 chữ số.

Ngày một phần hoặc cắt ngắn, tức là với độ chính xác thấp hơn ngày, không được chấp nhận. Dấu gạch nối -được yêu cầu trong mọi trường hợp. (Những điều kiện tiên quyết này giúp cho việc dẫn đầu +luôn luôn là tùy chọn.)

Quy tắc

Đây là môn đánh gôn. Mã ngắn nhất tính bằng byte thắng. Câu trả lời trước đó thắng một tie.

Các trường hợp thử nghiệm

Kiểm tra hợp lệ

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 

Cái cuối cùng là hợp lệ tùy chọn, tức là khoảng trắng ở đầu và cuối trong chuỗi đầu vào có thể được cắt bớt.

Định dạng không hợp lệ

-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

Ngày không hợp lệ

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
ngoài chủ đề, nhưng có thể hữu ích - Stack Overflow: stackoverflow.com/questions/28020805/ ((nếu tôi không nên đăng nó, hãy nói với tôi)
Daniele D

Điều gì xảy ra nếu lập trình viên là một YEC (Nhà sáng tạo Trái đất trẻ)?
Leaky Nun

Về -0000-08-10những gì là exaclty quyết định tùy ý? Không cho phép năm là 0 âm?
edc65

@ edc65 Có, +0000-08-100000-08-10nên được sử dụng thay thế. Tuy nhiên, xin lưu ý rằng câu trả lời được chấp nhận trong biến thể biểu thức chính quy của thử thách này không thành công trong trường hợp thử nghiệm cụ thể này, do đó, đây không thực sự là một điều kiện thất bại (nghĩa là không nên , không bắt buộc ).
Crissov

@KennyLau Thì lập trình viên đã sai .
Arcturus

Câu trả lời:


2

JavaScript (ES6), 236

236 byte cho phép âm 0 năm ( -0000). Trả về đúng hay sai

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

Thêm kiểm tra cho âm 0 cắt 2 byte nhưng thêm 13. Lưu ý rằng trong javascript, giá trị số -0tồn tại và nó được đặt đặc biệt bằng 0, nhưng 1/-0-Infinity. Phiên bản này trả về 0 hoặc 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)

Kiểm tra

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>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.