2012-04-25 34 views
6

Tôi biết rằng có những câu hỏi tương tự như tôi đã được trả lời, nhưng sau khi đọc qua chúng tôi vẫn không có giải pháp mà tôi đang tìm kiếm.Các ngày phù hợp với cụm từ thông dụng bằng Python?

Sử dụng Python 3.2.2, tôi cần khớp "Tháng, Ngày, Năm" với tháng là chuỗi, Ngày là hai chữ số không quá 30, 31 hoặc 28 cho tháng 2 và 29 cho tháng 2 trong năm nhuận . (Về cơ bản một ngày REAL và hợp lệ)

Đây là những gì tôi có cho đến nay:

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) 

tôi vẫn không quá quen thuộc với cú pháp regex vì vậy tôi có thể có nhân vật trong đó mà là không cần thiết (các [ ,] [] cho dấu phẩy và dấu cách giống như cách sai để đi về nó), nhưng khi tôi cố gắng khớp "Tháng 1, 26, 1991" trong tệp văn bản mẫu của tôi, việc in ra các mục trong "đối sánh" là ('Tháng một', '26', '1991', '19').

Tại sao '19' bổ sung xuất hiện ở cuối?

Ngoài ra, tôi có thể thêm hoặc thay đổi điều gì trong regex của mình để cho phép tôi xác thực ngày tháng chính xác? Kế hoạch của tôi bây giờ là chấp nhận gần như tất cả các ngày và loại bỏ chúng sau này bằng cách sử dụng các cấu trúc mức cao bằng cách so sánh nhóm ngày với nhóm tháng và năm để xem ngày đó có phải là < 31,30,29,28

Bất kỳ giúp đỡ sẽ được nhiều đánh giá cao bao gồm cả những lời chỉ trích xây dựng về cách tôi đang đi về thiết kế regex của tôi.

+5

Tại sao bạn cần sử dụng cụm từ thông dụng? (Bây giờ bạn có hai vấn đề ...) – geoffspear

+0

Tôi tin rằng báo @Wooble đề cập đến là 'Một số người, khi đối mặt với một vấn đề, hãy nghĩ "Tôi biết, tôi sẽ sử dụng cụm từ thông dụng." Bây giờ họ có hai vấn đề. ' và tôi có khuynh hướng đồng ý. Tôi khuyên bạn nên trích xuất một chuỗi và 2 số (có lẽ với một regex đơn giản, nhưng đơn giản chỉ bằng cách tách chuỗi trên dấu phẩy) và sau đó sử dụng datetime để kiểm tra xem ngày có hợp lệ hay không. –

+0

Cảm ơn lời khuyên, nhưng đây là một bài tập về nhà, nơi tôi được yêu cầu làm một biểu thức để phù hợp với ngày tháng. – ahabos

Trả lời

6

Dưới đây là một cách để tạo ra một biểu thức chính quy mà sẽ phù hợp với bất kỳ ngày định dạng mong muốn (mặc dù bạn rõ ràng có thể tinh chỉnh cho dù dấu phẩy là không bắt buộc, thêm chữ viết tắt tháng, và vân vân):

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 

Sau đó chúng tôi có:

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

Và regexp vinh quang này, bạn có thể hỏi là gì?

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

(ban đầu tôi có ý định làm một liệt kê lưỡi-in-cheek của ngày càng tốt, nhưng tôi về cơ bản đã kết thúc bằng tay bằng văn bản rằng điều toàn bộ tổng trừ cho bội số của bốn, anyway.)

+0

Cảm ơn vì điều đó! Tôi vẫn đang trải qua regexp bạn đã từ từ để phân tích và hiểu các thành phần riêng lẻ nhưng tôi thấy cách tốt nhất để thực hiện nó là nhóm các tháng với nhau về cơ bản không có sự khác biệt nào ngoài tên và tháng 2 riêng biệt phần còn lại và khớp với phần khác trong biểu thức – ahabos

+0

Tôi đã nói "không có cách nào dễ dàng" để tạo biểu thức chính quy kiểm tra tháng trước ngày tháng. Vì vậy, bạn đã cho thấy cách làm điều đó ... một cách khó khăn ... bạn, thưa bạn, là điên rồ, nhưng đó là loại tốt của sự điên rồ. +1! P.S. Tôi đặc biệt thích công cụ kiểm tra năm nhuận. – steveha

+0

mẫu = r '(% s) + (% s), *% s'% năm hiển thị lỗi cho tôi .. mẫu = '(% s) + (% s), *% s'% năm LoạiError: không đủ đối số cho chuỗi định dạng – monkey

1

Python có một phân tích cú pháp ngày như một phần của các mô-đun time:

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

Trên đây là tất cả các bạn cần nếu định dạng ngày luôn là như nhau. Vì vậy, trong mã sản xuất thực, tôi sẽ viết một biểu thức chính quy phân tích ngày tháng, và sau đó sử dụng các kết quả từ biểu thức chính quy để xây dựng một chuỗi ngày luôn có định dạng giống nhau.

Bây giờ bạn đã nói, trong phần bình luận, rằng đây là bài tập về nhà, tôi sẽ đăng một câu trả lời khác với các mẹo về cụm từ thông dụng.

+0

Tôi bắt buộc phải sử dụng cụm từ thông dụng vì đây là bài tập về nhà tôi đang đấu tranh với – ahabos

+0

Điều này tạo ra một đối tượng ngày nếu bạn có một chuỗi chỉ là ngày tháng, nhưng nó không hoạt động như một 'regex' để khớp ngày trong chuỗi hoặc văn bản lớn hơn. – Suz

2

Dưới đây là một số suy nghĩ nhanh:

Mọi người đề xuất bạn sử dụng một cái gì đó khác với biểu thức chính quy đều cung cấp cho bạn lời khuyên rất tốt. Mặt khác, luôn luôn là thời điểm tốt để tìm hiểu thêm về cú pháp biểu thức chính quy ...

Biểu thức trong dấu ngoặc vuông - [...] - khớp với bất kỳ ký tự đơn nào trong các dấu ngoặc đơn đó. Vì vậy, viết [,], chỉ chứa một ký tự đơn, giống hệt với cách viết một dấu phẩy đơn giản: ,.

Phương thức .findall trả về danh sách tất cả các nhóm phù hợp trong chuỗi. Một nhóm được xác định bởi parenthese - (...) - và chúng được tính từ trái sang phải, ngoài cùng bên ngoài. Biểu thức cuối cùng của bạn trông giống như sau:

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

Dấu ngoặc đơn bên ngoài khớp với cả năm và dấu ngoặc đơn bên trong khớp với hai chữ số đầu tiên. Do đó, trong một ngày như "1989", hai nhóm đối sánh cuối cùng sẽ là 198919.

+2

Hãy cho anh biết cách khắc phục, về các nhóm không phù hợp. (?: 19 | 20) – ricochet1k

+0

Không, tôi sẽ để bạn làm điều đó. Tôi không thực sự chắc chắn nó cần "sửa chữa", bởi vì không có gì "bị hỏng". Tôi chỉ muốn giải thích hành vi. – larsks

2

Một nhóm được xác định bằng dấu ngoặc đơn (...) và chúng được tính từ trái sang phải, ngoài cùng bên ngoài. Biểu thức cuối cùng của bạn trông giống như sau:

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

Dấu ngoặc đơn bên ngoài khớp với cả năm và dấu ngoặc đơn bên trong khớp với hai chữ số đầu tiên. Do đó, trong một ngày như "1989", hai nhóm kết hợp sẽ là 1989 và 19. Vì bạn không muốn nhóm bên trong (hai chữ số đầu tiên), bạn nên sử dụng một nhóm không bắt giữ thay thế. Các nhóm không bắt đầu bắt đầu bằng ?:, được sử dụng như sau: (?:a|b|c)

Bằng cách này, có một số tài liệu hay về cách sử dụng cụm từ thông dụng here.

0

Trước hết như tôi đã nói, tôi không nghĩ rằng cụm từ thông dụng là lựa chọn tốt nhất để giải quyết vấn đề này nhưng để trả lời câu hỏi của bạn. Bằng cách sử dụng dấu ngoặc đơn, bạn đang phân tách chuỗi thành một số nhóm con và khi bạn gọi hàm findall, bạn sẽ tạo một danh sách với tất cả nhóm khớp mà bạn đã tạo và chuỗi phù hợp.

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

Đây là vấn đề của bạn, regex sẽ phù hợp với cả năm toàn bộ và 19 hoặc 20 tuỳ thuộc vào việc đầu năm với 19 hoặc 20.

+0

Dấu ngoặc đơn của bạn không cân bằng. – ricochet1k

+0

Cảm ơn bạn đã không thấy điều đó. – danielz

1

Bạn có biểu thức chính quy này:

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

Một tính năng của cụm từ thông dụng là "lớp nhân vật". Các ký tự trong dấu ngoặc vuông tạo nên một lớp nhân vật. Do đó [,] là một lớp nhân vật khớp với một ký tự đơn, , (dấu phẩy). Bạn cũng có thể chỉ cần đặt dấu phẩy.

Có lẽ bạn muốn đặt dấu phẩy tùy chọn? Bạn có thể làm điều đó bằng cách đặt dấu chấm hỏi sau: ,?

Mọi thứ bạn đưa vào dấu ngoặc đơn sẽ tạo thành "nhóm đối sánh". Tôi nghĩ rằng "19" thêm bí ẩn đến từ một nhóm phù hợp mà bạn không có ý định. Bạn có thể làm cho một nhóm không phù hợp sử dụng cú pháp sau: (?:

Vì vậy, ví dụ:

r'(?:red|blue) socks' 

này sẽ phù hợp với "vớ đỏ" hoặc "vớ xanh" nhưng không làm cho một nhóm phù hợp. Nếu bạn sau đó đưa rằng bên trong dấu ngoặc đơn giản:

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

Điều đó sẽ làm cho một nhóm phù hợp, có giá trị sẽ là "red socks" hay "blue socks"

Tôi nghĩ rằng nếu bạn áp dụng những ý kiến ​​để biểu hiện thường xuyên của bạn, nó sẽ làm việc. Đó là chủ yếu là chính xác ngay bây giờ.

Để xác thực ngày tháng so với tháng, đó là cách vượt ra ngoài phạm vi của cụm từ thông dụng. Mẫu của bạn sẽ khớp với "February 31" và không có cách nào dễ dàng để khắc phục điều đó.

Các vấn đề liên quan