2011-09-26 30 views
12

Tôi không nói về các số dòng cụ thể bởi vì tôi đang đọc nhiều tệp có cùng định dạng nhưng thay đổi về độ dài.
Giả sử tôi có file văn bản này:python - Đọc tệp từ và tới các dòng văn bản cụ thể

Something here... 
... ... ... 
Start      #I want this block of text 
a b c d e f g 
h i j k l m n 
End      #until this line of the file 
something here... 
... ... ... 

Tôi hy vọng bạn biết những gì tôi có ý nghĩa. tôi đã suy nghĩ của iterating thông qua các tập tin sau đó tìm kiếm bằng cách sử dụng biểu thức chính quy để tìm số dòng "Start" và "End" sau đó sử dụng linecache để đọc từ dòng Bắt đầu để kết thúc dòng. Nhưng làm thế nào để có được số dòng? tôi có thể sử dụng chức năng nào?

+0

Câu hỏi này là rất tương tự như sau một http://stackoverflow.com/questions/7098530/repeatedly-extract-a-line-between-two-delimiters-in-a-text-file-python – salomonvh

Trả lời

21

Nếu bạn chỉ muốn các khối văn bản giữa Start và End, bạn có thể làm một cái gì đó đơn giản như:

with open('test.txt') as input_data: 
    # Skips text before the beginning of the interesting block: 
    for line in input_data: 
     if line.strip() == 'Start': # Or whatever test is needed 
      break 
    # Reads text until the end of the block: 
    for line in input_data: # This keeps reading the file 
     if line.strip() == 'End': 
      break 
     print line # Line is extracted (or block_of_lines.append(line), etc.) 

Trong thực tế, bạn không cần phải thao tác số dòng để đọc dữ liệu giữa điểm đánh dấu Bắt đầu và Kết thúc. Lôgic ("đọc cho đến ...") được lặp lại trong cả hai khối, nhưng nó khá rõ ràng và hiệu quả (các phương pháp khác thường liên quan đến việc kiểm tra một số trạng thái [trước khi khối/trong khối/cuối khối đạt], hình phạt thời gian).

1

này nên được một sự khởi đầu cho bạn:

started = False 
collected_lines = [] 
with open(path, "r") as fp: 
    for i, line in enumerate(fp.readlines()): 
     if line.rstrip() == "Start": 
      started = True 
      print "started at line", i # counts from zero ! 
      continue 
      if started and line.rstrip()=="End": 
      print "end at line", i 
      break 
      # process line 
      collected_lines.append(line.rstrip()) 

Các máy phát điện enumerate mất một máy phát điện và liệt kê các lần lặp lại. Ví dụ:

print list(enumerate("a b c".split())) 

in

[ (0, "a"), (1,"b"), (2, "c") ] 

CẬP NHẬT:

poster hỏi cho việc sử dụng một regex để phù hợp với dòng như "===" và "======":

import re 
print re.match("^=+$", "===")  is not None 
print re.match("^=+$", "======") is not None 
print re.match("^=+$", "=")  is not None 
print re.match("^=+$", "=abc") is not None 
print re.match("^=+$", "abc=") is not None 
3

Đây là thứ sẽ hoạt động:

data_file = open("test.txt") 
block = "" 
found = False 

for line in data_file: 
    if found: 
     block += line 
     if line.strip() == "End": break 
    else: 
     if line.strip() == "Start": 
      found = True 
      block = "Start" 

data_file.close() 
+0

đây là một thủ thuật gọn gàng – BPm

+3

@BPm: Đây là một ví dụ về "máy trạng thái hữu hạn" (http://en.wikipedia.org/wiki/Finite_state_machine): máy bắt đầu ở trạng thái "Chặn chưa tìm thấy" (tìm thấy == Sai), tiếp tục chạy trong trạng thái "Trong khối" (được tìm thấy == Đúng) và trong trường hợp này dừng lại khi "Kết thúc" được tìm thấy. Chúng có thể là một chút không hiệu quả (ở đây, 'tìm thấy' phải được kiểm tra cho mỗi dòng trong khối), nhưng máy nhà nước thường cho phép người ta thể hiện rõ ràng logic của các thuật toán phức tạp hơn. – EOL

+0

+1, vì đây là một ví dụ tốt về cách tiếp cận máy trạng thái hoàn toàn hợp lệ. – EOL

2

Bạn có thể sử dụng regex khá dễ dàng. Bạn có thể làm cho nó mạnh mẽ hơn khi cần thiết, dưới đây là một ví dụ đơn giản.

>>> import re 
>>> START = "some" 
>>> END = "Hello" 
>>> test = "this is some\nsample text\nthat has the\nwords Hello World\n" 
>>> m = re.compile(r'%s.*?%s' % (START,END),re.S) 
>>> m.search(test).group(0) 
'some\nsample text\nthat has the\nwords Hello' 
+0

+1: Ý tưởng rất hay: cái này nhỏ gọn và có thể rất hiệu quả vì mô đun 're' rất nhanh. Các thẻ START và END phải được buộc phải ở trên một dòng * theo chính mình *, mặc dù, trong biểu thức chính quy của bạn ('^… $'). – EOL

+0

Cảm ơn:) .. Tôi không nghĩ bạn có thể sử dụng^|| $ khi bạn sử dụng lại.S spec vì nó bao gồm các ký tự dòng mới, nghĩ rằng bạn cần phải nói rõ ràng '% s \ n. *?% S \ n' – pyInTheSky

+1

Bạn chắc chắn có thể sử dụng ^… $ trong trường hợp này, bằng cách thêm cờ re.MULTILINE (http://docs.python.org/dev/library/re.html#module-contents). – EOL

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