2017-04-14 106 views
1

我想查找字符串中滿足一定條件的字母索引。如果字母前的所有括號都是完成。如何根據條件查找字符串中的位置python

這是我

sen = 'abcd(fgji(l)jkpg((jgsdti))khgy)ghyig(a)gh' 

這是我做了什麼

lst = [(i.end()) for i in re.finditer('g', sen)] 
# lst 
# [7, 16, 20, 29, 32, 36, 40] 
count_open = 0 
count_close = 0 
for i in lst: 
    sent=sen[0:i] 
    for w in sent: 
     if w == '(': 
      count_open += 1 
     if w == ')': 
      count_close += 1  
     if count_open == count_close && count_open != 0: 
      c = i-1 
    break 

這是給我的C爲39,這是最後一個指標,但正確的答案應該是35作爲第二個最後g之前的括號完成。

+0

當你發現你信不破這是第一次,直到最後一次,這正是它在做什麼,對吧?我錯過了什麼嗎? –

+0

我一直在玩休息時間,但他們都給出了相同的結果 –

+1

順便說一句,你已經使用了按位布爾和,'&'而不是'和'。我相信在這種情況下,它們將實際上是等價的,但如果您的意思是布爾型,則應該使用'和',並且如果要按位和,則只使用'&'。 –

回答

3

您可以免除regex,簡單地使用堆棧跟蹤你的括號是否是平衡的,而你遍歷字符:

In [4]: def find_balanced_gs(sen): 
    ...:  stack = [] 
    ...:  for i, c in enumerate(sen): 
    ...:   if c == "(": 
    ...:    stack.append(c) 
    ...:   elif c == ")": 
    ...:    stack.pop() 
    ...:   elif c == 'g': 
    ...:    if len(stack) == 0: 
    ...:     yield i 
    ...: 

In [5]: list(find_balanced_gs(sen)) 
Out[5]: [31, 35, 39] 

在這裏使用堆棧是檢查均衡parans的「經典」方法。自從我從頭開始實施它已經有一段時間了,所以可能會有一些我沒有考慮過的邊緣案例。但這應該是一個好的開始。我已經創建了一個生成器,但是你可以使它成爲一個正常的函數,返回一個索引列表,第一個這樣的索引或最後一個這樣的索引。

+0

不錯! (並且看起來對我而言)。 – Triptych

+0

@Triptych他們說,這是一位老人,但是一個好人。當然,我可以使用遞歸,但這只是交易我的堆棧調用堆棧:) –

+0

是的,我寫了一個遞歸版本只是爲了練習/樂趣。堆棧更安全。 – Triptych

-1

您可以使用.index()查找字符串或列表中字符串或元素的索引。

把stringvar.index(字符串)這會給你的字符串的偏移量或索引。

+0

這並不能解決我的問題,我正在尋找我 –

1

保持你的想法,只是幾個事情了,看評論:

import re 

sen='abcd(fgji(l)jkpg((jgsdti))khgy)ghyig(a)gh' 


lst=[ (i.end()) for i in re.finditer('g', sen)] 
#lst 
#[7, 16, 20, 29, 32, 36, 40] 

for i in lst: 
    # You have to reset the count for every i 
    count_open= 0 
    count_close=0 
    sent=sen[0:i] 
    for w in sent: 
     if w=='(': 
      count_open+=1 
     if w==')': 
      count_close+=1  
    # And iterate over all of sent before comparing the counts 
    if count_open == count_close & count_open != 0: 
     c=i-1 
     break 
print(c) 
# 31 - actually the right answer, not 35 

但是,這是不是很有效,因爲你的字符串相同的部分在迭代多次。你可以把它更加高效,在遍歷字符串只有一次:

sen='abcd(fgji(l)jkpg((jgsdti))khgy)ghyig(a)gh' 

def find(letter, string): 
    count_open = 0 
    count_close = 0 
    for (index, char) in enumerate(sen): 
     if char == '(': 
      count_open += 1 
     elif char == ')': 
      count_close += 1 
     elif char == letter and count_close == count_open and count_open > 0: 
      return index 
    else: 
     raise ValueError('letter not found') 

find('g', sen) 
# 31 
find('a', sen) 
# ... 
# ValueError: letter not found 
+0

謝謝@Thierry對於這個解釋,我同意第二個是一個有效的方法,但是它會失敗,而不是字母?如果文字間隔並有文字,我們將不得不改變功能?另外,如果沒有返回值,我將如何將這個func應用於數據框。 –

1

@Thierry Lathuille的答案是非常好的。在這裏,我只是提出一些微小的變化,但並未聲稱他們是更好的:

out = [] # collect all valid 'g' 
ocount = 0 # only store the difference between open and closed 
for m in re.finditer('[\(\)g]', sen): # use re to preselect 
    L = m.group() 
    ocount += {'(':1, ')':-1, 'g':0}[L] # save a bit of typing 
    assert ocount >= 0     # enforce some grammar if you like 
    if L == 'g' and ocount == 0: 
     out.append(m.start()) 

out 
# [31, 35, 39] 
1

這是一個簡單的採用在OP代碼(並考慮到條件count_open != 0):

def get_idx(f, sen): 
    idx = [] 
    count_open= 0 
    count_close=0 

    for i, w in enumerate(sen): 
     if w == '(': 
      count_open += 1 
     if w == ')': 
      count_close += 1  
     if count_open == count_close & count_open != 0: 
      if w == f: 
       idx.append(i) 

    return idx 

get_idx('g', sen) 

日期:

[31, 35, 39]