2015-09-26 40 views
0

我在這裏和那裏找到了一些答案,但我無法確定構建我想要的東西的確切方法。如果您能提供幫助,請提前致謝。Maya/Python - 通過文本文件循環的函數,但某些行除外

我有多個文本文件,都是以相同的方式構建的,但每個文件都有不同的信息。我想遍歷每個文件並逐行返回相應的信息。另一方面,我有一些布爾值,用於定義文件中的某一行是否必須跳過。例如:「如果boolean1爲true且lineInTheCorrespondingFile = 40,則跳過該行,否則讀取它,但跳過第36和37行而不是」「。

的事情是我不知道如何着手的功能,知道哪些文件被打開該行被讀取如果它跳過與否。知道我需要在函數結束時獨立返回每一行。

這裏是到目前爲止我的代碼:

def locatorsDatas (self): 

    preset = cmds.optionMenu ("presetMenu", q = 1, v = 1) 
    rawFile = presetsDir + preset.lower() + ".txt" 

    with open(rawFile) as file: 
     file.seek (0) 
     for lineNum, line in enumerate(file, start = 1): 
      if lineNum > 8 : # Skip header 
       locator = eval (line) 
       locName = locator[0] 
       xVal = locator[1] 
       yVal = locator[2] 
       zVal = locator[3] 
       locScale = locator[4] 
       locColor = locator[5] 
       if locator == "": 
        break 

       return (locName, xVal, yVal, zVal, locScale, locColor) 

我不知道什麼值,我應該進入的功能,使其跳過我想要的線,知道我不能直接寫因爲每個文件不會在相同的行中斷開。 哦,它只返回文件的一行而不是分別。

希望它是明確的,你可以幫助我,再次感謝。

+1

所以你有一個文本文件,你想閱讀一些行而不是其他人?你想讀的行,你想要從它返回的信息?順便說一句,使用'eval()'函數應該非常小心。 – enigma

+0

首先,這不是特定於瑪雅人的問題,因此如果您只是刪除對它的任何引用,則可能會獲得更多幫助。只需將'rawFile'作爲'locatorsData'的一個參數並切出'cmds'模塊調用。 – chadrik

+0

此外,您的數據佈局似乎是複雜化的主要來源。你有權控制文件的寫入方式嗎?你可以使用[json](https://docs.python.org/2/library/json.html)或[pickle](https://docs.python.org/2/library/pickle.html),它支持序列化數據類型,如字典和列表?如果你能提供你需要閱讀的文件的前幾行的例子,我認爲它會有很大的幫助。最後,只要文件不是非常大,將所有數據合併到一個結構中,然後提取所需內容可能更有意義。 – chadrik

回答

0

我看到您的代碼有許多問題。

首先,你總是從第8行返回數據,而不是任何其他數據。如果您想要從文件中提取多個值,則可能需要使用yield而不是return來使您的函數成爲生成器。然後調用代碼可以使用for循環訪問數據,或將生成器傳遞給list或另一個接受任何迭代的函數。

def locatorsDatas(self): 
    # ... 
    lineNum, line in enumerate(file, start=1): 
     # ... 
     yield results 

如果您不能使用發電機,但需要你的函數返回連續行,你需要保存文件迭代器(或者也許是enumerate迭代纏着)外的函數的範圍內的某處。這意味着每次調用函數時都不需要重新打開文件。你可以這樣做:

def __init__(self): 
    preset = cmds.optionMenu ("presetMenu", q = 1, v = 1) 
    rawFile = presetsDir + preset.lower() + ".txt" 
    self.preset_file_enumerator = enumerate(open(rawFile)) # save the iterator on self 

def locatorsDatas(self): 
    try: 
     lineNum, line = next(self.preset_file_enumerator) # get a value from the iterator 
     # do your processing 
     return results 
    except StopIteration: 
     # do whatever is appropriate when there's no more data in the file here 
     raise ValueError("no more data") # such as raising an exception 

我看到的下一個問題是你如何處理每一行以獲得單獨的數據片段。你正在使用eval這是一個非常糟糕的主意,如果你正在處理的數據甚至有點委託。這是因爲eval將其參數解釋爲Python代碼。它可以做任何東西,包括從您的硬盤驅動器刪除文件!一個更安全的版本是ast.literal_eval,它只允許字符串包含Python文字(包括列表,字典和集合,但不包含變量查找,函數調用或其他更復雜的代碼)。

您也有一個錯誤檢查,我不認爲會做你想要的。 if locator == ""測試可能放置太遲,以避免早期行提取eval'd行數據的錯誤。並且您運行的語句break將導致函數退出而不返回任何內容。如果您只想跳過空白行,則應將檢查置於循環的頂部,並使用continue而不是break

現在我們終於可以得到你問的問題的標題問題。如果您想跳過基於各種標誌的特定行,則只需在循環中檢查這些標誌,然後執行continue即可跳過您不想閱讀的行。我並不完全明白你問一下有關標誌是如何傳遞的,但假設你可以給他們作爲參數,這裏的代碼怎麼會看草圖:

def locatorsDatas(self, skip_40=False, skip_50=True): 
    # open file, ... 
    for lineNum, line in enumerate(file, start = 1): 
     if (not line or 
      lineNum < 8 or 
      skip_40 and lineNum == 40 or 
      skip_50 and lineNum == 50): 
      continue 
     # parse the line 
     yield result 

顯然,你應該用你自己標記名稱和邏輯,而不是我爲示例代碼編寫的那些。如果你的邏輯更加複雜,你可能更喜歡爲每個標記使用單獨的if語句,而不是象我一樣將它們全部整合到一個單獨的條件中。

+0

哇!謝謝!這非常有幫助,我用自己的方式重新編寫了代碼,因爲我對python非常陌生,並且一切都很完美! :) – UKDP