2009-10-18 46 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