Индекс Python более одного раза - PullRequest
3 голосов
/ 01 августа 2010

Я знаю, что .index() вернется туда, где подстрока находится в python.Тем не менее, я хочу найти расположение подстроки в n-й раз, что будет работать так:

>> s = 'abcdefacbdea'
>> s.index('a')
0
>> s.nindex('a', 1)
6
>>s.nindex('a', 2)
11

Есть ли способ сделать это в Python?

Ответы [ 13 ]

7 голосов
/ 01 августа 2010

Как насчет ...

def nindex(mystr, substr, n=0, index=0):
    for _ in xrange(n+1):
        index = mystr.index(substr, index) + 1
    return index - 1

Obs: как str.index() делает, nindex() повышает ValueError, когда substr не найден.

1 голос
/ 01 августа 2010
>>> from re import finditer, escape
>>> from itertools import count, izip

>>> def nfind(s1, s2, n=1):
...    """return the index of the nth nonoverlapping occurance of s2 in s1"""
...    return next(j.start() for i,j in izip(count(1), finditer(escape(s2),s1)) if i==n)
...
>>> nfind(s,'a')
0
>>> nfind(s,'a',2)
6
>>> nfind(s,'a',3)
11
1 голос
/ 01 августа 2010

Вот запомнившаяся версия, которая максимально избегает напрасной работы, поддерживая что-то близкое [1] к вашим спецификациям (вместо того, чтобы делать что-то более разумное, например, циклически повторять все попадания; -) ...

[1]: просто закрыть - не может быть новый метод .nindex в строках, как вам требуется, конечно! -)

def nindex(haystack, needle, nrep=1, _memo={}):
  if nrep < 1:
    raise ValueError('%r < 1' % (nrep,))
  k = needle, haystack
  if k in _memo:
    where = _memo[k]
  else:
    where = _memo[k] = [-1]
  while len(where) <= nrep:
    if where[-1] is None:
      return -1
    w = haystack.find(needle, where[-1] + 1)
    if w < 0:
      where.append(None)
      return -1
    where.append(w)
  return where[nrep]

s = 'abcdefacbdea'
print nindex(s, 'a')
print nindex(s, 'a', 2)
print nindex(s, 'a', 3)

в соответствии с запросом выведите 0, затем 6, затем 11.

1 голос
/ 01 августа 2010

Я бы, вероятно, использовал

[index for index, value in enumerate(s) if s == 'a'][n]

или

from itertools import islice
next(islice((index for index, value in enumerate(s) if s == 'a'), n, None))

или вообще не занимался бы индексами.

1 голос
/ 01 августа 2010
def nindex(needle, haystack, index=1):
     parts = haystack.split(needle)
     position = 0
     length = len(needle)
     for i in range(index - 1):
         position += len(parts[i]) + length
     return position

Мне интересно посмотреть другие решения, я не чувствую, что это особенно питонически.

1 голос
/ 01 августа 2010

Да. Напишите цикл, используя s.index('yourstring', start)

Обновление после нахождения большого жира -1 ... я не написал некоторый код ???

Вот моя попытка погашения, которая позволяет не перекрываться при желании и проверяется в показанной степени:

>>> def nindex(haystack, needle, n, overlapping=True):
...    delta = 1 if overlapping else max(1, len(needle))
...    start = -delta
...    for _unused in xrange(n):
...       start = haystack.index(needle, start+delta)
...    return start
...
>>> for n in xrange(1, 11):
...    print n, nindex('abcdefacbdea', 'a', n)
...
1 0
2 6
3 11
4
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 5, in nindex
ValueError: substring not found
>>> for olap in (True, False):
...    for n in (1, 2):
...       print str(olap)[0], n, nindex('abababab', 'abab', n, olap)
...
T 1 0
T 2 2
F 1 0
F 2 4
>>> for n in xrange(1, 8):
...    print n, nindex('abcde', '', n)
...
1 0
2 1
3 2
4 3
5 4
6 5
7
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 5, in nindex
ValueError: substring not found
>>>
0 голосов
/ 31 марта 2016

Этот выполняет работу в регулярном выражении .. что НЕ (ПОСЛЕ ТЕСТИРОВАНИЯ) потенциально быстрее, если вы изменили его для кэширования скомпилированного регулярного выражения (или запомнили его).

import re

def nindex(s, substr, n = 1):
    """Find the nth occurrence of substr in s."""
    safe_substr = re.escape(substr) 
    regex_str = ".*?(?:%s.*?){%i}(%s).*?" % (safe_substr, n - 1, safe_substr)
    regex = re.compile(regex_str)
    match = regex.search(s)    
    if match is None:
        index = None
    else:
        index = match.start(1)        
    return index


# The rest of this code is just test cases...
for search_str in ("a", "bc"):
    print "Looking for %s" % search_str
    for test_str in ('abcdefacbdea',
                     'abcdefacbdeaxxx',
                     'xxxabcdefacbdeaxxx'):
        for i in (0, 1, 2, 3, 4):      
            print("%s %i index: %s" % 
                  (test_str, i, nindex(test_str, search_str, i)))
    print 

Вывод:

Looking for a
abcdefacbdea 0 index: None
abcdefacbdea 1 index: 0
abcdefacbdea 2 index: 6
abcdefacbdea 3 index: 11
abcdefacbdea 4 index: None
abcdefacbdeaxxx 0 index: None
abcdefacbdeaxxx 1 index: 0
abcdefacbdeaxxx 2 index: 6
abcdefacbdeaxxx 3 index: 11
abcdefacbdeaxxx 4 index: None
xxxabcdefacbdeaxxx 0 index: None
xxxabcdefacbdeaxxx 1 index: 3
xxxabcdefacbdeaxxx 2 index: 9
xxxabcdefacbdeaxxx 3 index: 14
xxxabcdefacbdeaxxx 4 index: None

Looking for bc
abcdefacbdea 0 index: None
abcdefacbdea 1 index: 1
abcdefacbdea 2 index: None
abcdefacbdea 3 index: None
abcdefacbdea 4 index: None
abcdefacbdeaxxx 0 index: None
abcdefacbdeaxxx 1 index: 1
abcdefacbdeaxxx 2 index: None
abcdefacbdeaxxx 3 index: None
abcdefacbdeaxxx 4 index: None
xxxabcdefacbdeaxxx 0 index: None
xxxabcdefacbdeaxxx 1 index: 4
xxxabcdefacbdeaxxx 2 index: None
xxxabcdefacbdeaxxx 3 index: None
xxxabcdefacbdeaxxx 4 index: None

Вот памятная версия:

def memoized_hedgehog_nindex(s, substr, n = 1, _memoized_regexes = {}):
    safe_substr = re.escape(substr) 
    regex_str = ".*?(?:%s.*?){%i}(%s).*?" % (safe_substr, n - 1, safe_substr)

    # memoize
    key = (n, safe_substr)
    if key in _memoized_regexes:
        regex = _memoized_regexes[key]
    else:
        regex = re.compile(regex_str)
        _memoized_regexes[key] = regex

    match = regex.search(s)    
    if match is None:
        index = None
    else:
        index = match.start(1)        
    return index
0 голосов
/ 01 августа 2010

Как насчет ...

# index is 0-based
def nindex(needle, haystack, index=0):
     parts = haystack.split(needle)
     if index >= len(parts)-1:
         return -1
     return sum(len(x) for x in parts[:index+1])+index*len(needle)
0 голосов
/ 01 августа 2010

Просто вызовите «index» несколько раз, используя результат последнего вызова (+ 1) в качестве начальной позиции:

def nindex(needle, haystack, n):
"find the nth occurrence of needle in haystack"
  pos = -1
  for dummy in range(n):
    pos = haystack.index(needle, pos + 1)
  return pos

Примечание: я не проверял.

0 голосов
/ 01 августа 2010
import re

def nindex(text, n=1, default=-1):
    return next(
        itertools.islice((m.start() for m in re.finditer('a', text)), n - 1, None),
        default
    )

print nindex(s)
print nindex(s, 1)
print nindex(s, 2)
print nindex(s, 3)
print nindex(s, 4)
...