2013-04-11 49 views
3

我有一個文本文件的完整數據與閱讀,直到一個點的Python

#Name 
#main 

然後啓動它,然後許多數字,然後將該文件與

#extra 
!side 

所以這裏有一個結束小片段

#Name 
#main 
60258960 
33031674 
72302403 
#extra 
!side 

我想只讀取數字。但是,這是一腳,我希望他們每個人都是他們自己的單獨的字符串。

所以我知道如何讀頭後開始

read=f.readlines()[3:] 

但我難倒一切。有什麼建議麼?

回答

3

你很接近,因爲你是。您只需要修改您的列表片段,以將前兩個文件中的最後兩行切掉。 readlines自然會返回一個列表,其中每個項目是文件中的一行。但是,它在每個字符串的末尾也會有「換行符」,因此您可能需要將其過濾掉。

with open("myfile.txt") as myfile: 
    # Get only numbers 
    read = myfile.readlines()[2:-2] 

# Remove newlines 
read = [number.strip() for number in read] 
print read 
+1

你可以用'read = myfile.read()。splitlines()[2:-2]'幾乎同時去掉換行符。 – martineau

+0

請注意'.strip()'也會去掉任何前導/尾部空格或製表符。你可以使用'number.rstrip(「\ n」)'來避免這種情況。 (這與OP的問題無關,但可能對讀者有用) – bfontaine

4

逐行閱讀。使用#main作爲標誌來開始處理。使用#extra作爲標誌來停止處理。

start = '#main' 
end = '#extra' 
numbers = [] 
file_handler = open('read_up_to_a_point.txt') 
started = False 
for line in file_handler: 
    if end in line: 
     started = False  
    if started: 
     numbers.append(line.strip()) 
    if start in line: 
     started = True 
file_handler.close() 
print numbers 

樣本輸出

蟒蛇read_up_to_a_point.py [ '60258960', '33031674', '72302403']

1

我會做這樣的事情:

nums = [] 
for line in f: 
    stripped = line.rstrip('\n') 
    if stripped.isnumeric(): 
    nums.append(stripped) 

nums只包含那些數字的那些行。如果你的數字是正確的,意味着不是負數,而不是十六進制。這將需要一個正則表達式來精確匹配。

1

如果您知道您的輸入文件可以很好地適應內存,則只應使用.readlines();它一次讀取所有行。

大多數情況下,您可以一次讀取一條輸入行,並且您可以迭代文件句柄對象。

當你要特別,棘手的輸入處理,我建議封裝處理在發電機的功能是這樣的:

def do_something_with_point(point): 
    print(point) 

class BadInputFile(ValueError): 
    pass 

def read_points_data(f): 
    try: 
     line = next(f) 
     if not line.startswith("#Name"): 
      raise BadInputFile("file does not start with #Name") 

     line = next(f) 
     if not line.startswith("#main"): 
      raise BadInputFile("second line does not start with #main") 
    except StopIteration: 
     raise BadInputFile("truncated input file") 

    # use enumerate() to count input lines; start at line number 3 
    # since we just handled two lines of header 
    for line_num, line in enumerate(f, 3): 
     if line.startswith("#extra"): 
      break 
     else: 
      try: 
       yield int(line) 
      except ValueError: 
       raise BadInputFile("illegal line %d: %s" % (line_num, line)) 
      # if you really do want strings: yield line 
    else: 
     # this code will run if we never see a "#extra" line 
     # if break is executed, this doesn't run. 
     raise BadInputFile("#extra not seen") 

    try: 
     line = next(f) 
     if not line.startswith("!side"): 
      raise BadInputFile("!side not seen after #extra") 
    except StopIteration: 
     raise BadInputFile("input file truncated after #extra") 

with open("points_input_file.txt") as f: 
    for point in read_points_data(f): 
     do_something_with_point(point) 

注意,此輸入功能徹底驗證輸入,引發異常時什麼是不正確的輸入。但是使用輸入數據的循環簡單而乾淨;使用read_points_data()的代碼可以很整齊。

我製作的read_points_data()將輸入點轉換爲int值。如果你真的想要點作爲字符串,你可以修改代碼;我在那裏留言,提醒你。

+0

認真?看起來像是尋找問題的解決方案......而這個問題中的問題不在於此。 – martineau

+0

@martineau我認爲這是一個很好的答案。也許提問者可能不會檢查輸入,但我認爲驗證輸入數據並沒有錯,而且這個答案顯示瞭如何在自己的函數中隱藏所有的驗證。注意使用數據的'for'循環是乾淨整潔的,儘管檢查非常徹底......發生器是我喜歡Python的東西之一。 – steveha

+0

如果解決OP的問題,那麼將輸入文件的讀取封裝在生成器函數中的想法可能具有一些優點。但恕我直言,你的示例代碼會更好,如果它只是說明了核心概念。我並不是說輸入驗證和錯誤處理並不重要,但這個問題與他們無關。你可以指出,你的技術可以幫助他們做到這一點,而不必在其所有的榮耀中這樣做。在答案的代碼中很難[參見樹木的森林](http://en.wiktionary.org/wiki/see_the_forest_for_the_trees#Verb)。 – martineau

1

這並不總是一個好主意(或者甚至是可行的)使用readlines()不帶參數,因爲它會在整個文件中讀取,並可能消耗大量的內存—和做,如果你不可能沒有必要一次不需要所有人,這取決於你在做什麼。

所以,一種方法是使用Python 生成器函數從文件中提取所需的行或值。它們非常容易創建,基本上只需使用yield語句返回值而不是return。從編程的角度來看,它們之間的主要區別在於,下次調用函數時,執行將繼續執行yield語句後面的行,而不是像通常情況下從第一行開始。這意味着它們的內部狀態會在後續調用之間自動保存,這使得在內部進行復雜的處理變得更加容易。

下面是一個非常簡單的例子,它使用一個獲取文件中您想要的數據,每次只增加一行,因此它不需要足夠的內存來保存整個文件:

def read_data(filename): 
    with open(filename, 'rt') as file: 
     next(file); next(file) # ignore first two lines 
     value = next(file).rstrip('\n') # read what should be the first number 
     while value != '#extra': # not end-of-numbers marker 
      yield value 
      value = next(file).rstrip('\n') 

for number in read_data('mydatafile'): 
    # process each number string produced 

當然,你還可以收集它們放在一起放入一個列表,如果你願意的話,像這樣:

numbers = list(read_data('mydatafile')) 

正如你可以看到它可能做其他有用的東西,在功能,如驗證文件數據的格式或以其他方式對其進行預處理。在上面的例子中,我通過在它返回的列表的每一行中刪除換行字符readlines()來完成一些操作。通過使用yield int(value)而不是僅僅yield value將每個字符串值轉換爲整數也是微不足道的。

希望這會給你足夠的想法,以確定什麼是可能的,以及在決定使用什麼方法來執行手頭任務時所涉及的折衷。

+0

由於您正在文本模式下打開文件,因此您應該使用'\ n'來表示行結束。你可能想使用「通用換行」模式:https://docs.python.org/2/library/functions.html?highlight=open#open由於'file'是一個內置關鍵字,我通常不會使用'file'作爲標識符。但那些是尼特;我喜歡答案。 – steveha

+0

@ steveha:謝謝 - 畢竟,只是你自己的想法有一點不同。你說得對,只需要''\ n'',但是在'rU''模式下打開文件並不是因爲在'文本模式'下打開文件 - 'r''和''rt ''都這麼做 - 意味着將啓用平臺相關的換行符處理。這意味着無論是否在所使用的Python解釋器中啓用了通用換行符支持,它們都將轉換爲單一字符「\ n」,只是它將由操作系統處理(可能會更快)。 – martineau