5 Stimmen

Stringabdeckungsoptimierung in Python

Ich habe diesen Ausgangsstring.

'bananaappleorangestrawberryapplepear'

Und habe auch ein Tupel mit Strings:

('apple', 'plepe', 'leoran', 'lemon')

Ich möchte eine Funktion haben, so dass ich aus dem Ausgangsstring und dem Tupel mit Strings folgendes erhalte:

'bananaxxxxxxxxxgestrawberryxxxxxxxar'

Ich weiß, wie man es imperativ macht, indem man für jedes Wort das Wort im Ausgangsstring findet und dann Buchstabe für Buchstabe in allen ursprünglichen Stringen mit ausgetauschten Wörtern durchläuft.

Aber das ist nicht sehr effizient und hässlich. Ich vermute, dass es eine elegantere Möglichkeit gibt, dies auf funktionale Weise mit itertools oder etwas anderem zu tun. Wenn du eine Python-Bibliothek kennst, die dies effizient tun kann, lass es mich bitte wissen.

UPDATE: Justin Peel wies auf einen Fall hin, den ich in meiner ursprünglichen Frage nicht beschrieben habe. Wenn ein Wort 'aaa' ist und 'aaaaaa' im ursprünglichen String enthalten ist, sollte die Ausgabe wie 'xxxxxx' aussehen.

3voto

Ned Batchelder Punkte 342778
import re

words = ('apple', 'plepe', 'leoran', 'lemon')
s = 'bananaappleorangestrawberryapplepear'

x = set()

for w in words:
    for m in re.finditer(w, s):
        i = m.start()
        for j in range(i, i+len(w)):
            x.add(j)

result = ''.join(('x' if i in x else s[i]) for i in range(len(s)))
print result

ergibt:

bananaxxxxxxxxxgestrawberryxxxxxxxar

1voto

Justin Peel Punkte 46114

Hier ist eine weitere Antwort. Es gibt möglicherweise einen schnelleren Weg, um die Buchstaben durch x zu ersetzen, aber ich denke nicht, dass es notwendig ist, da dies bereits ziemlich schnell ist.

import re

def do_xs(s,pats):
    pat = re.compile('('+'|'.join(pats)+')')

    sout = list(s)
    i = 0
    match = pat.search(s)
    while match:
        span = match.span()
        sout[span[0]:span[1]] = ['x']*(span[1]-span[0])
        i = span[0]+1
        match = pat.search(s,i)
    return ''.join(sout)

txt = 'bananaappleorangestrawberryapplepear'
pats = ('apple', 'plepe', 'leoran', 'lemon')
print do_xs(txt,pats)

Im Grunde erstelle ich ein Regex-Muster, das mit einem der Eingabemuster übereinstimmt. Dann starte ich die Suche immer wieder neu, beginnend 1 nach der Startposition des zuletzt gefundenen Treffers. Es könnte jedoch ein Problem geben, wenn eines der Eingabemuster ein Präfix eines anderen Eingabemusters ist.

1voto

eternicode Punkte 6667

Annehmen, dass wir ohne stdlib und andere Importe arbeiten müssen:

s1 = 'bananaappleorangestrawberryapplepear'
t = ('apple', 'plepe', 'leoran', 'lemon')
s2 = s1

solution = 'bananaxxxxxxxxxgestrawberryxxxxxxxar'

for word in t:
    if word not in s1: continue
    index = -1 # Start at -1 so our index search starts at 0
    for iteration in range(s1.count(word)):
        index = s1.find(word, index+1)
        length = len(word)
        before = s2[:index]
        after = s2[index+length:]
        s2 = before + 'x'*length + after

print s2 == solution

1voto

aeter Punkte 10812
>>> string_ = 'bananaappleorangestrawberryapplepear'
>>> words = ('apple', 'plepe', 'leoran', 'lemon')
>>> xes = [(string_.find(w), len(w)) for w in words]
>>> xes
[(6, 5), (29, 5), (9, 6), (-1, 5)]
>>> for index, len_ in xes:
...   if index == -1: continue
...   string_ = string_.replace(string_[index:index+len_], 'x'*len_)
...
>>> string_
'bananaxxxxxxxxxgestrawberryxxxxxxxar'
>>

Es gibt sicherlich effektivere Wege, aber die vorzeitige Optimierung ist die Wurzel allen Übels.

0voto

Falmarri Punkte 46357
a = ('Apfel', 'Apfelbaum', 'Apfelsine', 'Zitrone')
b = 'BananeApfelOrangenerdbeereApfelBirne'

for obst in a:
    if obst in b:
        b = b.replace(obst, Anzahl von X'en)

Das einzige, was du jetzt tun musst, ist zu bestimmen, wie viele Xe du ersetzen sollst.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X