2009-10-18 48 views
1

说,我们有一个多层迭代的一些字符串在“最后”的水平,是字符串是可迭代的,但我觉得你得到了我的意思:grep的多层迭代相匹配的字符串(Python)的

['something', 
('Diff', 
('diff', 'udiff'), 
('*.diff', '*.patch'), 
('text/x-diff', 'text/x-patch')), 

('Delphi', 
('delphi', 'pas', 'pascal', 'objectpascal'), 
('*.pas',), 
('text/x-pascal',['lets', 'put one here'],)), 

('JavaScript+Mako', 
('js+mako', 'javascript+mako'), 
('application/x-javascript+mako', 
'text/x-javascript+mako', 
'text/javascript+mako')), 
... 
] 

是否有任何方便的方法,我可以实现一个搜索,会给我的匹配字符串的索引?我想东西会起到这样的事情(在上面的列表data):

>>> grep('javascript', data) 

,它会返回[(2,1,1),(2,2,0),(2, 2,1),(2,2,2)]也许。也许我错过了一种类似的解决方案,它不会返回任何结果,但可以帮助我找到一些字符串迭代器的迭代列表中的一些字符串。

我写了一点点,但它似乎少年和不雅的,所以我想我会问这里。我想我可以继续嵌套异常,就像我在这里开始的那样,将函数支持的层次数嵌套起来,但我希望得到一些整洁,抽象,pythonic的东西。

import re 

def rgrep(s, data): 
    ''' given a iterable of strings or an iterable of iterables of strings, 

    returns the index/indices of strings that contain the search string. 

    Args:: 

     s - the string that you are searching for 
     data - the iterable of strings or iterable of iterables of strings 
    ''' 


    results = [] 
    expr = re.compile(s) 
    for item in data: 
     try: 
      match = expr.search(item) 
      if match != None: 
       results.append(data.index(item)) 

     except TypeError: 
      for t in item: 
       try: 
        m = expr.search(t) 
        if m != None: 
         results.append((list.index(item), item.index(t))) 

       except TypeError: 
        ''' you can only go 2 deep! ''' 
        pass 

    return results 
+0

这将有助于你展示你到目前为止的内容,以及你自己的解决方案的哪一部分给你带来麻烦。 – 2009-10-18 13:15:47

回答

3

我从grepping分裂递归枚举:

def enumerate_recursive(iter, base=()): 
    for index, item in enumerate(iter): 
     if isinstance(item, basestring): 
      yield (base + (index,)), item 
     else: 
      for pair in enumerate_recursive(item, (base + (index,))): 
       yield pair 

def grep_index(filt, iter): 
    return (index for index, text in iter if filt in text) 

这样,你既可以做非递归和递归grepping:我们正在使用

l = list(grep_index('opt1', enumerate(sys.argv))) # non-recursive 
r = list(grep_index('diff', enumerate_recursive(your_data))) # recursive 

还要注意迭代器在这里,如果需要的话可以保存更长序列的RAM。

更通用的解决方案将是给一个可调用的,而不是字符串grep_index。但是这可能对你没有必要。

+0

我喜欢你的解决方案比我的更好:) – unutbu 2009-10-18 15:31:19

+0

是的,这很好,谢谢。 – 2009-10-18 16:11:59

+0

注:在for ...:yield pair部分中的'pair可能会被更新的python实现中的'yield from'结构所替代。 – liori 2014-11-27 20:42:38

0

要获得位置使用enumerate()

>>> data = [('foo', 'bar', 'frrr', 'baz'), ('foo/bar', 'baz/foo')] 
>>> 
>>> for l1, v1 in enumerate(data): 
...  for l2, v2 in enumerate(v1): 
...    if 'f' in v2: 
...      print l1, l2, v2 
... 
0 0 foo 
1 0 foo/bar 
1 1 baz/foo 

在这个例子中,我使用一个简单的比赛'foo' in bar但你可能使用正则表达式的工作。

显然,enumerate()可提供超过2级的支持,在后期编辑。

1

下面是一个使用递归搜索的数据结构的grep的。

请注意,良好的数据结构带来了优雅的解决方案。 错误的数据结构使您向后弯曲以适应。 这对我来说就像其中一个糟糕的数据结构阻碍 而不是帮助你的情况之一。

由于采用了具有更均匀的结构 (而不是使用此grep的)一个简单的数据结构可能是值得研究。

#!/usr/bin/env python 

data=['something', 
('Diff', 
('diff', 'udiff'), 
('*.diff', '*.patch'), 
('text/x-diff', 'text/x-patch',['find','java deep','down'])), 

('Delphi', 
('delphi', 'pas', 'pascal', 'objectpascal'), 
('*.pas',), 
('text/x-pascal',['lets', 'put one here'],)), 

('JavaScript+Mako', 
('js+mako', 'javascript+mako'), 
('application/x-javascript+mako', 
'text/x-javascript+mako', 
'text/javascript+mako')), 
] 

def grep(astr,data,prefix=[]): 
    result=[] 
    for idx,elt in enumerate(data): 
     if isinstance(elt,basestring): 
      if astr in elt: 
       result.append(tuple(prefix+[idx])) 
     else: 
      result.extend(grep(astr,elt,prefix+[idx])) 
    return result 

def pick(data,idx): 
    if idx: 
     return pick(data[idx[0]],idx[1:]) 
    else: 
     return data 
idxs=grep('java',data) 
print(idxs) 
for idx in idxs: 
    print('data[%s] = %s'%(idx,pick(data,idx))) 
+0

为什么不是isinstance(elt,basestring)? – liori 2009-10-18 14:13:31

+0

谢谢,我不知道basestring! – unutbu 2009-10-18 14:21:39