2017-04-14 104 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]