Wie finde ich mehrere Vorkommen einer Zeichenfolge in einer Zeichenfolge in Python? Bedenken Sie:
>>> text = "Allowed Hello Hollow"
>>> text.find("ll")
1
>>>
Das erste Auftreten von ll
ist also wie erwartet bei 1. Wie finde ich das nächste Auftreten davon?
Die gleiche Frage gilt für eine Liste. Erwägen:
>>> x = ['ll', 'ok', 'll']
Wie finde ich alle ll
mit ihren Indizes?
Antworten:
Mit regulären Ausdrücken können Sie
re.finditer
alle (nicht überlappenden) Vorkommen finden:>>> import re >>> text = 'Allowed Hello Hollow' >>> for m in re.finditer('ll', text): print('ll found', m.start(), m.end()) ll found 1 3 ll found 10 12 ll found 16 18
Wenn Sie den Overhead regulärer Ausdrücke nicht möchten, können Sie alternativ auch wiederholt
str.find
den nächsten Index abrufen:>>> text = 'Allowed Hello Hollow' >>> index = 0 >>> while index < len(text): index = text.find('ll', index) if index == -1: break print('ll found at', index) index += 2 # +2 because len('ll') == 2 ll found at 1 ll found at 10 ll found at 16
Dies funktioniert auch für Listen und andere Sequenzen.
quelle
find
. Aber es funktioniert mitindex
, Sie müssen nurexcept ValueError
anstatt auf -1 zu testenindex += 1
stattdessen).index += 2
Sache, wenn man dies auf den String ‚lllll‘ anwenden, wird es zwei von vier Vorkommen von ‚ll‘ verpassen. Am besten auchindex += 1
für Saiten.Ich denke, was Sie suchen, ist
string.count
"Allowed Hello Hollow".count('ll') >>> 3
Hoffe, dies hilft
HINWEIS: Dies erfasst nur nicht überlappende Vorkommen
quelle
Verwenden Sie für das Listenbeispiel ein Verständnis:
>>> l = ['ll', 'xx', 'll'] >>> print [n for (n, e) in enumerate(l) if e == 'll'] [0, 2]
Ähnliches gilt für Strings:
>>> text = "Allowed Hello Hollow" >>> print [n for n in xrange(len(text)) if text.find('ll', n) == n] [1, 10, 16]
Dadurch werden benachbarte Läufe von "ll" aufgelistet, die möglicherweise Ihren Wünschen entsprechen oder nicht:
>>> text = 'Alllowed Hello Holllow' >>> print [n for n in xrange(len(text)) if text.find('ll', n) == n] [1, 2, 11, 17, 18]
quelle
FWIW, hier sind ein paar Nicht-RE-Alternativen, die meiner Meinung nach besser sind als die Lösung von Poke .
Der erste verwendet
str.index
und prüft aufValueError
:def findall(sub, string): """ >>> text = "Allowed Hello Hollow" >>> tuple(findall('ll', text)) (1, 10, 16) """ index = 0 - len(sub) try: while True: index = string.index(sub, index + len(sub)) yield index except ValueError: pass
Der zweite Test verwendet
str.find
und prüft den Sentinel von,-1
indem er Folgendes verwendetiter
:def findall_iter(sub, string): """ >>> text = "Allowed Hello Hollow" >>> tuple(findall_iter('ll', text)) (1, 10, 16) """ def next_index(length): index = 0 - length while True: index = string.find(sub, index + length) yield index return iter(next_index(len(sub)).next, -1)
Um eine dieser Funktionen auf eine Liste, ein Tupel oder eine andere iterierbare Zeichenfolge anzuwenden, können Sie eine übergeordnete Funktion verwenden - eine, die eine Funktion als eines ihrer Argumente verwendet - wie diese:
def findall_each(findall, sub, strings): """ >>> texts = ("fail", "dolly the llama", "Hello", "Hollow", "not ok") >>> list(findall_each(findall, 'll', texts)) [(), (2, 10), (2,), (2,), ()] >>> texts = ("parallellized", "illegally", "dillydallying", "hillbillies") >>> list(findall_each(findall_iter, 'll', texts)) [(4, 7), (1, 6), (2, 7), (2, 6)] """ return (tuple(findall(sub, string)) for string in strings)
quelle
Für Ihr Listenbeispiel:
In [1]: x = ['ll','ok','ll'] In [2]: for idx, value in enumerate(x): ...: if value == 'll': ...: print idx, value 0 ll 2 ll
Wenn Sie alle Elemente in einer Liste haben möchten, die 'll' enthält, können Sie dies auch tun.
In [3]: x = ['Allowed','Hello','World','Hollow'] In [4]: for idx, value in enumerate(x): ...: if 'll' in value: ...: print idx, value ...: ...: 0 Allowed 1 Hello 3 Hollow
quelle
>>> for n,c in enumerate(text): ... try: ... if c+text[n+1] == "ll": print n ... except: pass ... 1 10 16
quelle
Ganz neu in der Programmierung im Allgemeinen und in einem Online-Tutorial. Ich wurde gebeten, dies ebenfalls zu tun, aber nur mit den Methoden, die ich bisher gelernt hatte (im Grunde Strings und Loops). Ich bin mir nicht sicher, ob dies hier einen Mehrwert bringt, und ich weiß, dass Sie es nicht so machen würden, aber ich habe es dazu gebracht, damit zu arbeiten:
needle = input() haystack = input() counter = 0 n=-1 for i in range (n+1,len(haystack)+1): for j in range(n+1,len(haystack)+1): n=-1 if needle != haystack[i:j]: n = n+1 continue if needle == haystack[i:j]: counter = counter + 1 print (counter)
quelle
Diese Version sollte eine lineare Länge der Zeichenfolge haben und in Ordnung sein, solange sich die Sequenzen nicht zu oft wiederholen (in diesem Fall können Sie die Rekursion durch eine while-Schleife ersetzen).
def find_all(st, substr, start_pos=0, accum=[]): ix = st.find(substr, start_pos) if ix == -1: return accum return find_all(st, substr, start_pos=ix + 1, accum=accum + [ix])
Das Listenverständnis von bstpierre ist eine gute Lösung für kurze Sequenzen, scheint jedoch quadratisch komplex zu sein und hat einen von mir verwendeten Langtext nie fertiggestellt.
findall_lc = lambda txt, substr: [n for n in xrange(len(txt)) if txt.find(substr, n) == n]
Für eine zufällige Zeichenfolge mit nicht trivialer Länge ergeben die beiden Funktionen dasselbe Ergebnis:
import random, string; random.seed(0) s = ''.join([random.choice(string.ascii_lowercase) for _ in range(100000)]) >>> find_all(s, 'th') == findall_lc(s, 'th') True >>> findall_lc(s, 'th')[:4] [564, 818, 1872, 2470]
Die quadratische Version ist jedoch etwa 300-mal langsamer
%timeit find_all(s, 'th') 1000 loops, best of 3: 282 µs per loop %timeit findall_lc(s, 'th') 10 loops, best of 3: 92.3 ms per loop
quelle
#!/usr/local/bin python3 #-*- coding: utf-8 -*- main_string = input() sub_string = input() count = counter = 0 for i in range(len(main_string)): if main_string[i] == sub_string[0]: k = i + 1 for j in range(1, len(sub_string)): if k != len(main_string) and main_string[k] == sub_string[j]: count += 1 k += 1 if count == (len(sub_string) - 1): counter += 1 count = 0 print(counter)
Dieses Programm zählt die Anzahl aller Teilzeichenfolgen, auch wenn sie sich ohne Verwendung von Regex überlappen. Dies ist jedoch eine naive Implementierung. Um im schlimmsten Fall bessere Ergebnisse zu erzielen, wird empfohlen, entweder Suffix Tree, KMP oder andere String-Matching-Datenstrukturen und -Algorithmen zu verwenden.
quelle
Hier ist meine Funktion zum Auffinden mehrerer Vorkommen. Im Gegensatz zu den anderen Lösungen hier werden die optionalen Start- und Endparameter für das Schneiden unterstützt, genau wie
str.index
:def all_substring_indexes(string, substring, start=0, end=None): result = [] new_start = start while True: try: index = string.index(substring, new_start, end) except ValueError: return result else: result.append(index) new_start = index + len(substring)
quelle
Ein einfacher iterativer Code, der eine Liste von Indizes zurückgibt, in denen der Teilstring vorkommt.
def allindices(string, sub): l=[] i = string.find(sub) while i >= 0: l.append(i) i = string.find(sub, i + 1) return l
quelle
Sie können teilen, um relative Positionen zu erhalten, dann aufeinanderfolgende Zahlen in einer Liste summieren und gleichzeitig hinzufügen (Zeichenfolgenlänge * Vorkommensreihenfolge), um die gewünschten Zeichenfolgenindizes zu erhalten.
>>> key = 'll' >>> text = "Allowed Hello Hollow" >>> x = [len(i) for i in text.split(key)[:-1]] >>> [sum(x[:i+1]) + i*len(key) for i in range(len(x))] [1, 10, 16] >>>
quelle
Vielleicht nicht so pythonisch, aber etwas selbsterklärender. Es gibt die Position des Wortes zurück, das in der ursprünglichen Zeichenfolge enthalten ist.
def retrieve_occurences(sequence, word, result, base_counter): indx = sequence.find(word) if indx == -1: return result result.append(indx + base_counter) base_counter += indx + len(word) return retrieve_occurences(sequence[indx + len(word):], word, result, base_counter)
quelle
Ich denke, es ist nicht nötig, die Länge des Textes zu testen. finde einfach weiter, bis nichts mehr zu finden ist. So was:
>>> text = 'Allowed Hello Hollow' >>> place = 0 >>> while text.find('ll', place) != -1: print('ll found at', text.find('ll', place)) place = text.find('ll', place) + 2 ll found at 1 ll found at 10 ll found at 16
quelle
Sie können dies auch mit dem folgenden bedingten Listenverständnis tun:
string1= "Allowed Hello Hollow" string2= "ll" print [num for num in xrange(len(string1)-len(string2)+1) if string1[num:num+len(string2)]==string2] # [1, 10, 16]
quelle
Ich hatte diese Idee erst vor einiger Zeit zufällig bekommen. Die Verwendung einer While-Schleife mit String-Spleißung und String-Suche kann auch bei überlappenden Strings funktionieren.
findin = "algorithm alma mater alison alternation alpines" search = "al" inx = 0 num_str = 0 while True: inx = findin.find(search) if inx == -1: #breaks before adding 1 to number of string break inx = inx + 1 findin = findin[inx:] #to splice the 'unsearched' part of the string num_str = num_str + 1 #counts no. of string if num_str != 0: print("There are ",num_str," ",search," in your string.") else: print("There are no ",search," in your string.")
Ich bin ein Amateur in Python-Programmierung (eigentlich Programmierung einer beliebigen Sprache) und bin mir nicht sicher, welche anderen Probleme es haben könnte, aber ich denke, es funktioniert gut?
Ich denke, lower () könnte bei Bedarf auch irgendwo darin verwendet werden.
quelle