2009-12-07 3 views
4

Я хотел бы реализовать команду unix `grep -r 'в функции python. Я знаю о command.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 ] 

, но это, конечно, не использует регулярное выражение, он просто проверяет, «ул» подстрока «л». поэтому я пробовал следующее:

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

Кроме того, структура и цель вашего кода совершенно скрыта. Я пифонизировал его.

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

+0

О, его естественное желание использовать мощные абстракции! Я использовал для создания чудовищных многострочных конструкций map() и reduce() до того, как возникли соображения списка - мне очень понравилась идея «сделайте это, для всех THESE» вместо «Ok, сделайте следующий и сделайте ... Хорошо, сделай следующий и делай ... »Но я узнал, что мои коллеги не могут распутать его, и это точно так же, как на компьютере. –

+0

Если вам нравится этот орфографический корректор, вы должны изучить haskell. Функциональные отображения на множествах являются естественными http://github.com/timrobinson/spell-correct/blob/master/Correct.hs –

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 + х 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 Я быстро смог настроить это, чтобы использовать более надежный более широкий набор опций. –