web-dev-qa-db-fra.com

nombre de chaînes avec occurrences qui se chevauchent

Quel est le meilleur moyen de compter le nombre d'occurrences d'une chaîne donnée, y compris les chevauchements en python? est-ce le moyen le plus évident:

def function(string, str_to_search_for):
      count = 0
      for x in xrange(len(string) - len(str_to_search_for) + 1):
           if string[x:x+len(str_to_search_for)] == str_to_search_for:
                count += 1
      return count


function('1011101111','11')
returns 5

?

ou y a-t-il un meilleur moyen en python?

45
calccrypto

Eh bien, ceci pourrait être plus rapide puisqu'il fait la comparaison en C:

def occurrences(string, sub):
    count = start = 0
    while True:
        start = string.find(sub, start) + 1
        if start > 0:
            count+=1
        else:
            return count
64
Jochen Ritzel
>>> import re
>>> text = '1011101111'
>>> len(re.findall('(?=11)', text))
5

Si vous ne voulez pas charger la liste complète des correspondances dans la mémoire, ce ne sera jamais un problème! vous pouvez le faire si vous vouliez vraiment:

>>> sum(1 for _ in re.finditer('(?=11)', text))
5

En tant que fonction (re.escape s'assure que la sous-chaîne n'interfère pas avec l'expression régulière):

>>> def occurrences(text, sub):
        return len(re.findall('(?={0})'.format(re.escape(sub)), text))

>>> occurrences(text, '11')
5
36
jamylak

Vous pouvez également essayer d'utiliser le new Python regex module , qui prend en charge les correspondances qui se chevauchent.

import regex as re

def count_overlapping(text, search_for):
    return len(re.findall(search_for, text, overlapped=True))

count_overlapping('1011101111','11')  # 5
9
David C

str.count de Python compte les sous-chaînes ne se chevauchant pas:

In [3]: "ababa".count("aba")
Out[3]: 1

Voici quelques façons de compter les séquences qui se chevauchent, je suis sûr qu'il y en a beaucoup d'autres :)

Expressions régulières Look-ahead

Comment trouver des correspondances qui se chevauchent avec une expression rationnelle?

In [10]: re.findall("a(?=ba)", "ababa")
Out[10]: ['a', 'a']

Générer toutes les sous-chaînes

In [11]: data = "ababa"
In [17]: sum(1 for i in range(len(data)) if data.startswith("aba", i))
Out[17]: 2
8
Dima Tisnek
s = "bobobob"
sub = "bob"
ln = len(sub)
print(sum(sub == s[i:i+ln] for i in xrange(len(s)-(ln-1))))
3

Comment trouver un motif dans une autre chaîne avec un chevauchement

Cette fonction (une autre solution!) Reçoit un motif et un texte. Renvoie une liste avec toutes les sous-chaînes situées dans et leurs positions.

def occurrences(pattern, text):
    """
    input: search a pattern (regular expression) in a text
    returns: a list of substrings and their positions 
    """
    p = re.compile('(?=({0}))'.format(pattern))
    matches = re.finditer(p, text)
    return [(match.group(1), match.start()) for match in matches]

print (occurrences('ana', 'banana'))
print (occurrences('.ana', 'Banana-fana fo-fana'))

[('ana', 1), ('ana', 3)] 
[('Bana', 0), ('nana', 2), ('fana', 7), ('fana', 15)]

3
Jose Raul Barreras
def count_substring(string, sub_string):
    count = 0
    for pos in range(len(string)):
        if string[pos:].startswith(sub_string):
            count += 1
    return count

Cela pourrait être le moyen le plus simple.

2
Arun Tom

Ma réponse à la question Bob sur le parcours:

s = 'azcbobobegghaklbob'
total = 0
for i in range(len(s)-2):
    if s[i:i+3] == 'bob':
        total += 1
print 'number of times bob occurs is: ', total
2
Luke D

Une façon assez pythonique serait d'utiliser la compréhension de liste ici, bien que ce ne soit probablement pas la plus efficace.

sequence = 'abaaadcaaaa'
substr = 'aa'

counts = sum([
    sequence.startswith(sub, i) for i in range(len(sequence))
])
print(counts)  # 5

La liste serait [False, False, True, False, False, False, True, True, False, False] car elle vérifie tous les index dans la chaîne, et parce que int(True) == 1, sum nous donne le nombre total de correspondances.

1
ParkerD
def count_substring(string, sub_string):
    counter = 0
    for i in range(len(string)):
        if string[i:].startswith(sub_string):
        counter = counter + 1
    return counter

Le code ci-dessus parcourt simplement une fois la chaîne et continue de vérifier si une chaîne commence par la sous-chaîne particulière en cours de comptage.

1
Anshul Tiwari

Voici ma solution edX MIT "find bob" * (* trouver le nombre d'occurrences "bob" dans une chaîne nommée s), qui compte essentiellement les occurrences de chevauchement d'une sous-chaîne donnée:

s = 'azcbobobegghakl'
count = 0

while 'bob' in s:
    count += 1 
    s = s[(s.find('bob') + 2):]

print "Number of times bob occurs is: {}".format(count)
1
dasdachs

Cela peut être résolu en utilisant regex.

import re
def function(string, sub_string):
    match = re.findall('(?='+sub_string+')',string)
    return len(match)
1
Himanshu Bhagwani

Si les chaînes sont grandes, vous voulez utiliser Rabin-Karp , en résumé:

  • une fenêtre déroulante de la taille d'une sous-chaîne, se déplaçant sur une chaîne
  • un hachage avec O(1) surcharge pour ajouter et supprimer (c'est-à-dire se déplacer de 1 caractère)
  • mis en œuvre en C ou en s'appuyant sur pypy
0
Dima Tisnek

Ceci est un autre exemple d'utilisation de str.find() mais beaucoup de réponses le rendent plus compliqué que nécessaire:

def occurrences(text, sub):
    c, n = 0, text.find(sub)
    while n != -1:
        c += 1
        n = text.find(sub, n+1)
    return c

In []:
occurrences('1011101111', '11')

Out[]:
5
0
AChampion

Donné

sequence = '1011101111'
sub = "11"

Code

Dans ce cas particulier:

sum(x == Tuple(sub) for x in Zip(sequence, sequence[1:]))
# 5

Plus généralement, cela

windows = Zip(*([sequence[i:] for i, _ in enumerate(sequence)][:len(sub)]))
sum(x == Tuple(sub) for x in windows)
# 5

ou s'étendre aux générateurs:

import itertools as it


iter_ = (sequence[i:] for i, _ in enumerate(sequence))
windows = Zip(*(it.islice(iter_, None, len(sub))))
sum(x == Tuple(sub) for x in windows)

Alternative

Vous pouvez utiliser more_itertools.locate :

import more_itertools as mit


len(list(mit.locate(sequence, pred=lambda *args: args == Tuple(sub), window_size=len(sub))))
# 5
0
pylang

Fonction qui prend en entrée deux chaînes et compte le nombre de fois que sub se produit dans une chaîne, y compris les chevauchements. Pour vérifier si sub est une sous-chaîne, j'ai utilisé l'opérateur in

def count_Occurrences(string, sub):
    count=0
    for i in range(0, len(string)-len(sub)+1):
        if sub in string[i:i+len(sub)]:
            count=count+1
    print 'Number of times sub occurs in string (including overlaps): ', count
0
Aquila3000

Pour une copie question j’ai décidé de la compter 3 sur 3 et de comparer la chaîne, par exemple.

counted = 0

for i in range(len(string)):

    if string[i*3:(i+1)*3] == 'xox':
       counted = counted +1

print counted
0
AndreL
def count_overlaps (string, look_for):
    start   = 0
    matches = 0

    while True:
        start = string.find (look_for, start)
        if start < 0:
            break

        start   += 1
        matches += 1

    return matches

print count_overlaps ('abrabra', 'abra')
0
doublep

Une alternative très proche de la réponse acceptée, mais utilisant while comme test if au lieu d'inclure if dans la boucle:

def countSubstr(string, sub):
    count = 0
    while sub in string:
        count += 1
        string = string[string.find(sub) + 1:]
    return count;

Cela évite while True: et est un peu plus propre à mon avis

0
stevoblevo