2009-12-07 75 views
4

我想在python函數中實現unix命令'grep -r'。我知道有關commands.getstatusoutput(),但現在我不想使用它。我想出了這個:grep -r python

def grep_r (str, dir): 
    files = [ o[0]+"/"+f for o in os.walk(dir) for f in o[2] if os.path.isfile(o[0]+"/"+f) ] 
    return [ l for f in files for l in open(f) if str in l ] 

但這當然不使用正則表達式,它只是檢查是否「STR」是「L」的子字符串。所以我嘗試以下內容:

def grep_r (pattern, dir): 
    r = re.compile(pattern) 
    files = [ o[0]+"/"+f for o in os.walk(dir) for f in o[2] if os.path.isfile(o[0]+"/"+f) ] 
    return [ l for f in files for l in open(f) if r.match(l) ] 

但這不起作用,即使前一個函數做了也不會給我任何匹配。什麼改變了?我可以把它分成一堆嵌套循環,但我更感興趣的是簡潔而不可讀。

回答

5

re.match只檢查字符串的開頭。

使用re.search()

the docs

python提供基於正則表達式 兩種不同的原始 操作:匹配檢查匹配 只在字符串的開頭, ,同時搜索檢查字符串中任何位置的匹配項 (這是默認情況下Perl會執行的操作)。

8

您可能要search()而不是match()趕上比賽中的行中間,如http://docs.python.org/library/re.html#matching-vs-searching

注意另外,你的代碼的結構和意圖是相當隱蔽。我已經python化它。

def grep_r (pattern, dir): 
    r = re.compile(pattern) 
    for parent, dnames, fnames in os.walk(dir): 
     for fname in fnames: 
      filename = os.path.join(parent, fname) 
      if os.path.isfile(filename): 
       with open(filename) as f: 
        for line in f: 
         if r.search(line): 
          yield line 
+0

是的,我的是幾乎沒有可讀的,自從我讀this article by Peter Norvig我一直把那些「我爲我的some_generator '在我的代碼語句... – aaronstacy 2009-12-07 22:24:16

+0

哦,它的自然要使用強大的抽象!在列表推導出現之前,我曾經使用map()和reduce()的怪異多行構造 - 我真的很喜歡「做到這一切,而不是」的想法,而不是「好吧,下一個做...」確定下一個,然後......「但我知道我的同事無法解開它,這與計算機完全一樣。 – 2009-12-07 22:31:21

+0

如果你喜歡拼寫糾正器,你應該學習haskell。集合上的函數映射是一個自然的http://github.com/timrobinson/spell-correct/blob/master/Correct.hs – 2009-12-07 22:34:50

2
import os, re 

def grep_r(regex, dir): 
    for root, dirs, files in os.walk(dir): 
     for f in files: 
      for m in grep(regex, os.path.join(root, f)): 
       yield m 

def grep(regex, filename): 
    for i, line in enumerate(open(filename)): 
     if re.match(regex, line): # or re.search depending on your default 
      yield "%s:%d: %s" % (os.path.basename(filename), i+1, line) 
1

爲什麼你需要使用正則表達式?

path=os.path.join("/dir1","dir2","dir3") 
pattern="test" 
for r,d,f in os.walk(path): 
    for files in f: 
     for n,line in enumerate(open(os.path.join(r,files))): 
      if pattern in line: 
       print "%s found in line: %d of file: %s" %(pattern, n+1, files) 
3

把所有的代碼放到一個名爲pygrep和chmod + X pygrep:

#!/usr/bin/python 

import os 
import re 
import sys 

def file_match(fname, pat): 
    try: 
     f = open(fname, "rt") 
    except IOError: 
     return 
    for i, line in enumerate(f): 
     if pat.search(line): 
      print "%s: %i: %s" % (fname, i+1, line) 
    f.close() 


def grep(dir_name, s_pat): 
    pat = re.compile(s_pat) 
    for dirpath, dirnames, filenames in os.walk(dir_name): 
     for fname in filenames: 
      fullname = os.path.join(dirpath, fname) 
      file_match(fullname, pat) 

if len(sys.argv) != 3: 
    u = "Usage: pygrep <dir_name> <pattern>\n" 
    sys.stderr.write(u) 
    sys.exit(1) 

grep(sys.argv[1], sys.argv[2]) 
+0

+1我很快就能夠對此進行自定義,以使用更強大的一組選項。 – 2010-01-19 22:15:36