2011-09-22 10 views
5

Xem xét mẫu văn bản sau,Python - đơn vs multiline REGEX

#goals: dấu thời gian báo cáo quy trình, ví dụ: 2011-09-21 15:45:00 và hai thống kê đầu tiên trong succ. thống kê dòng, ví dụ:

input_text = ''' 
# Process_Name  (23387) Report at 2011-09-21 15:45:00.001 Type: Periodic #\n 
some line 1\n 
some line 2\n 
some other lines\n 
succ. statistics |  1438  1439 99 | 3782245 3797376 99 |\n 
some lines\n 
Process_Name  (23387) Report at 2011-09-21 15:50:00.001 Type: Periodic #\n 
some line 1\n 
some line 2\n 
some other lines\n 
succ. statistics |  1436  1440 99 | 3782459 3797523 99 |\n 
repeat the pattern several hundred times... 
''' 

tôi nhận nó làm việc khi lặp lại dòng đến dòng,

def parse_file(file_handler, patterns): 

    results = [] 
    for line in file_handler: 
     for key in patterns.iterkeys(): 
      result = re.match(patterns[key], line) 
      if result: 
       results.append(result) 

return results 

patterns = { 
    'report_date_time': re.compile('^# Process_Name\s*\(\s*\d+\) Report at (.*)\.[0-9] {3}\s+Type:\s*Periodic\s*#\s*.*$'), 
    'serv_term_stats': re.compile('^succ. statistics \|\s+(\d+)\s+ (\d+)+\s+\d+\s+\|\s+\d+\s+\d+\s+\d+\s+\|\s*$'), 
    } 
results = parse_file(fh, patterns) 

trở

[('2011-09-21 15:40:00',), 
('1425', '1428'), 
('2011-09-21 15:45:00',), 
('1438', '1439')] 

nhưng có một danh sách các đầu ra tuples như tôi mục tiêu,

[('2011-09-21 15:40:00','1425', '1428'), 
('2011-09-21 15:45:00', '1438', '1439')] 

Tôi đã thử nhiều combo với mẫu ban đầu và một lượng hóa lười biếng giữa họ, nhưng không thể tìm ra cách để nắm bắt các mô hình sử dụng một regex multiline

# .+? Lazy quantifier "match as few characters as possible (all characters allowed) until reaching the next expression" 
pattern = '# Process_Name\s*\(\s*\d+\) Report at (.*)\.[0-9]{3}\s+Type:\s*Periodic.*?succ. statistics) \|\s+(\d+)\s+(\d+)+\s+\d+\s+\|\s+\d+\s+\d+\s+\d+\s+\|\s' 
regex = re.compile(pattern, flags=re.MULTILINE) 

data = file_handler.read()  
for match in regex.finditer(data): 
    results = match.groups() 

Làm thế nào tôi có thể thực hiện điều này?

+0

Tôi không có một câu trả lời cho bạn, nhưng tại sao bạn nhúng \ n trong một chuỗi nhiều đường như vậy? Các dòng mới trong chuỗi là các dòng mới. – geoffspear

+0

Right Wooble, đây là trong Linux vì vậy chỉ cần thêm chúng để thể hiện các ký tự dòng mới (cố gắng để tránh bình thường là nó \ n hoặc \ r hoặc \ r \ n?) –

Trả lời

8

Sử dụng re.DOTALL nên . sẽ phù hợp với bất kỳ ký tự, bao gồm cả dòng mới:

import re 

data = ''' 
# Process_Name  (23387) Report at 2011-09-21 15:45:00.001 Type: Periodic #\n 
some line 1\n 
some line 2\n 
some other lines\n 
succ. statistics |  1438  1439 99 | 3782245 3797376 99 |\n 
some lines\n 
repeat the pattern several hundred times... 
''' 

pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*?succ. statistics\s+\|\s+(\d+)\s+(\d+)' 
regex = re.compile(pattern, flags=re.MULTILINE|re.DOTALL) 

for match in regex.finditer(data): 
    results = match.groups() 
    print(results) 

    # ('2011-09-21', '1438', '1439') 
+0

Wow. Bạn thật nhanh. Cảm ơn câu trả lời và cải tiến unutbu, và nhờ stackoverflow cho rất kinh nghiệm như bạn! –

+0

Chỉnh sửa: Một vết sưng nhỏ, tôi cần phải garantee một quantifier không tham lam, khác mà regex sẽ chỉ nắm bắt dấu thời gian đầu tiên, số liệu thống kê cuối cùng, bỏ qua hàng nghìn dòng ở giữa. Do đó, pattern = r '(\ d {4} - \ d {2} - \ d {2} \ d {2}: \ d {2}: \ d {2}). *? Succ. số liệu thống kê \ s + \ | \ s + (\ d +) \ s + (\ d +) ' –

+0

@JoaoFigueiredo: Ah điểm tốt. Cảm ơn vì sự đúng đắn của bạn. – unutbu