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?
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
>>> 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
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
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 :)
Comment trouver des correspondances qui se chevauchent avec une expression rationnelle?
In [10]: re.findall("a(?=ba)", "ababa")
Out[10]: ['a', 'a']
In [11]: data = "ababa"
In [17]: sum(1 for i in range(len(data)) if data.startswith("aba", i))
Out[17]: 2
s = "bobobob"
sub = "bob"
ln = len(sub)
print(sum(sub == s[i:i+ln] for i in xrange(len(s)-(ln-1))))
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)]
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.
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
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.
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.
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)
Cela peut être résolu en utilisant regex.
import re
def function(string, sub_string):
match = re.findall('(?='+sub_string+')',string)
return len(match)
Si les chaînes sont grandes, vous voulez utiliser Rabin-Karp , en résumé:
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
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
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
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
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')
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