2010-06-09 53 views
3

基本上是問題狀態。我對Python相當陌生,喜歡通過看和做來學習。使用Python搜索一個.txt文件以獲得單詞或短語列表(並顯示上下文)

我想要創建一個腳本來搜索文本文檔(比如從新聞文章中複製和粘貼的文本)以查找某些單詞或短語。理想情況下,單詞和短語的列表將存儲在一個單獨的文件中。

當獲得結果時,獲得結果的上下文將是非常好的。所以也許它可以在找到的每個搜索詞前後在文本文件中打印出50個字符。如果它也顯示搜索詞的搜索結果,它會很酷。

任何關於如何編碼的指針,甚至代碼示例都將不勝感激。

+0

您的功課? ;) – Aivar 2013-01-18 20:37:37

回答

3

從這樣的事情開始。此代碼並不是您所具有的規範的完全解決方案,但它是一個很好的起點。

import sys 

words = "foo bar baz frob" 

word_set = set(words.split()) 
for line_number, line in enumerate(open(sys.argv[1])): 
    if words_set.intersection(line.split()): 
     print "%d:%s" % (line_number, line.strip()) 

下面幾點說明:

  • 正在尋求被存儲在一個字符串最初(第3行)的話。我沿着空格分隔這個單詞列表並創建一個列表,以便檢查是否在單詞列表中找到當前行中的任何單詞。 (在一個集合上的成員資格檢查是O(1),而在列表上是O(n))。

  • 在主for循環中,我打開輸入文件(作爲命令行參數傳遞),並使用內置方法獲取行號計數器以及實際行。 sys.argv是存儲命令行參數的數組; sys.argv[0]始終是Python腳本的名稱。

  • 在循環本身中,我採用當前行,將其拆分爲單個單詞並再次創建單詞集。然後,我可以快速將當前行中的單詞集與我正在查找的單詞集相交。如果交叉點具有邏輯值True(即,如果它不是空的),則我打印行號以及行。

的東西都沒有解決(留給了你):

  • 單詞列表現在硬編碼在源代碼,但它不應該太難開一個額外的文件(其名稱被傳入,例如sys.argv[2]),逐個讀取它的文字並將它們存儲在一個集合中。請注意,您可以通過它們的addupdate方法擴展集(而不是用於列表的appendextend)。

  • 顯然,如果您有詞組而不是單詞(如其中一個註釋中指出的那樣),上述方法不起作用。因爲我假設你想學習,並且你不需要一個確切的解決方案,所以我只會說,如果你在一個集合中有短語,你可以通過說any(phrase in line for phrase in set_of_phrases)來檢查是否有任何集合元素在一行中。這可以用來代替設定的交集(當然,在這種情況下不要將您的行分成單詞)。

  • 如果要打印命中的上下文,可以使用兩個額外的變量(比如說,prev_linenext_line),它存儲上一行和下一行。在for循環中,實際上您將讀取的是next_line而不是line,並且在for循環結束時,應該注意將line複製到prev_linenext_line中,複製到line中。

  • 一個甚至更Python跟蹤先前的和下一個線以及的方式是創建一個產生由項目的元組一個Python發生器功能的i-1,項目和項目我+1每個i給定一個可迭代(如文件)。不過,這是更高級的東西,因爲對於Python來說相當陌生,所以我認爲最好先留下來。但是,如果你很好奇,生成函數完成這個任務可能是這樣的:

    def context_generator(iterable): 
        prev, current, next = None, None, None 
        for element in iterable: 
         prev, current, next = current, next, element 
         if current is not None: 
          yield prev, current, next 
        if next is not None: 
         yield current, next, None 
    
+0

*打開輸入文件*你需要使用'open'。 – SilentGhost 2010-06-09 17:17:56

+0

當然,我的不好,謝謝。 – 2010-06-09 17:21:00

+0

這也不適用於短語,只是單個單詞。 – FogleBird 2010-06-09 17:22:51

6

儘管對許多Python社區的一部分正則表達式經常表示反感,他們真的很一個用於適當用例的寶貴工具 - 這肯定包括識別單詞和短語(由於正則表達式模式中的「單詞邊界」元素 - 基於字符串處理的替代方法更加成爲一個問題,例如,.split()使用空格作爲分隔符,因此煩人地將標點符號附加到它旁邊的單詞等等)。

如果RE的都OK,我建議是這樣的:

import re 
import sys 

def main(): 
    if len(sys.argv) != 3: 
    print("Usage: %s fileofstufftofind filetofinditin" % sys.argv[0]) 
    sys.exit(1) 

    with open(sys.argv[1]) as f: 
    patterns = [r'\b%s\b' % re.escape(s.strip()) for s in f] 
    there = re.compile('|'.join(patterns)) 

    with open(sys.argv[2]) as f: 
    for i, s in enumerate(f): 
     if there.search(s): 
     print("Line %s: %r" % (i, s)) 

main() 

的第一個參數是(路徑)用的詞或短語的文本文件發現,每行一個,第二個參數( )在其中找到它們的文本文件的路徑。這很容易,如果需要的話,使病例檢索不敏感(也許只是基於可選命令行選項開關),等等,等等

一些解釋讀者不熟悉的RE ...:

patterns項目中的\b項目確保不會發生意外匹配(如果您正在搜索「貓」或「狗」,您將不會看到「目錄」或「失敗者」的意外擊中;並且你不會錯過「貓,微笑,逃跑」中的一擊,它被一些分裂的思想認爲有「貓」這個詞,包括逗號;-)。

|項意味着or,例如,從內容的文本文件(兩行)

cat 
dog 

這將形成較長的單詞中的模式'\bcat\b|\bdog\b'將定位要麼「貓」和「狗」(作爲獨立的話,忽略標點符號,但拒絕命中)。

re.escape轉義標點符號,所以它的字面匹配,而不是像它通常在RE模式中具有的特殊含義。

+0

再一次,感謝您的答覆 - 一些代碼與解釋是非常有幫助的。我曾想過關於RE,但不知道在這種情況下它是否相關 - 很高興看到它! – prupert 2010-06-10 07:47:35

相關問題