2016-09-07 10 views
4

Ich habe einen Satz, sagen wir mal:Wie kann ich Teile von Satz in Python umkehren?

Der schnelle braune Fuchs springt über den faulen Hund

ich eine Funktion erstellen möchten, die zwei Argumente übernimmt, einen Satz und eine Liste der Dinge zu ignorieren. Und es gibt diesen Satz mit den umgekehrten Wörtern zurück, aber es sollte das Zeug ignorieren, das ich ihm in einem zweiten Argument übergebe. Dies ist, was ich im Moment haben:

def main(sentence, ignores): 
    return ' '.join(word[::-1] if word not in ignores else word for word in sentence.split()) 

Aber das wird nur funktionieren, wenn ich eine zweite Liste übergeben, wie so:

print(main('The quick brown fox jumps over the lazy dog', ['quick', 'lazy'])) 

Allerdings möchte ich eine Liste wie diese passieren:

print(main('The quick brown fox jumps over the lazy dog', ['quick brown', 'lazy dog'])) 

erwartetes Ergebnis: ehT quick brown xof spmuj revo eht lazy dog

Also im Grunde der zweiten Das Argument (die Liste) enthält Teile des Satzes, die ignoriert werden sollen. Nicht nur einzelne Wörter.

Muss ich Regexp dafür verwenden? Ich habe versucht, es zu vermeiden ...

+0

Sie sind die Worte oder den vollen Satz zu ignorieren? –

+0

Ich versuche ganze Sätze zu ignorieren. – Bravi

+0

Also, wenn braun später erschien, sollte es nicht schnellstens umgekehrt werden? –

Antwort

0

statt Platzhalter, warum nicht nur am Anfang jede Phrase umkehren, die Sie rund um den richtigen Weg sein wollen, dann kehrt die gesamte Zeichenfolge:

def main(sentence, ignores): 
    for phrase in ignores: 
     reversed_phrase = ' '.join([word[::-1] for word in phrase.split()]) 
     sentence = sentence.replace(phrase, reversed_phrase) 

    return ' '.join(word[::-1] for word in sentence.split()) 

print(main('The quick brown fox jumps over the lazy dog', ['quick', 'lazy'])) 
print(main('The quick brown fox jumps over the lazy dog', ['quick brown', 'lazy dog'])) 

kehrt:

ehT quick nworb xof spmuj revo eht lazy god 
ehT quick brown xof spmuj revo eht lazy dog 
+0

Was ist, wenn du '['faul Hund', 'schnell braun']' hast? – furas

+0

Dies ist keine schlechte Idee, aber es erfordert, dass die "Liste" der Phrasen, die unverändert bleiben sollen, der Satzstruktur in beiden Wiederholungen entspricht (alle Instanzen einer Phrase können nicht einzeln ignoriert werden) und Reihenfolge ("ignores" muss der im Satz genau gesehenen Reihenfolge entsprechen). – ShadowRanger

+0

ich denke, dass Sie zuerst nach dem Index suchen können, dass jede Phrase im Satz gefunden wird, dann Sortierung Ignoriert durch diesen Index und dann die Ersetzungen. – SuperShoot

0

ich bin die erste Person, die Vermeidung von regulären Ausdrücken zu empfehlen, aber in diesem Fall ohne die Komplexität zu tun, ist größer als die Komplexität durch ihre Verwendung hinzugefügt:

import re 

def main(sentence, ignores): 
    # Dedup and allow fast lookup for determining whether to reverse a component 
    ignores = frozenset(ignores) 

    # Make a pattern that will prefer matching the ignore phrases, but 
    # otherwise matches each space and non-space run (so nothing is dropped) 
    # Alternations match the first pattern by preference, so you'll match 
    # the ignores phrases if possible, and general space/non-space patterns 
    # otherwise 
    pat = r'|'.join(map(re.escape, ignores)) + r'|\S+|\s+' 

    # Returns the chopped up pieces (space and non-space runs, but ignore phrases stay together 
    parts = re.findall(pat, sentence) 

    # Reverse everything not found in ignores and then put it all back together 
    return ''.join(p if p in ignores else p[::-1] for p in parts) 
+0

Warum 'frozenset' statt nur' set'? –

+0

@StefanPochmann: Absolut kein Grund, außer dass wir es später nicht ändern werden. In der Praxis glaube ich nicht, dass es einen Unterschied macht (aktuelle Versionen von Python führen keine speziellen Optimierungen für "frozenset" durch; die internen Strukturen für 'set' und' frozenset' sind identisch, so dass, wenn Sie es nie mutieren, der einzige Unterschied besteht eignet sich für die Verwendung als "dict" -Schlüssel oder "set" -Mitglied, aber ich verwende "frozenset", wenn es nicht mutiert werden soll; kostet nichts, kann bei Bedarf jederzeit geändert werden. Wenn Phrasen untereinander Subphrasen sein könnten, sollten Sie 'collections.OrderedDict' verwenden, um die Reihenfolge zu erhalten. – ShadowRanger

+0

Dieser ist ziemlich sauber und lesbar, ich habe nur versucht, Regex zu vermeiden .. – Bravi

0

eine andere Idee einfach, Reverse jedes Wort und dann die ignoriert umkehren rechts zurück:

>>> from functools import reduce 
>>> def main(sentence, ignores): 
     def r(s): 
      return ' '.join(w[::-1] for w in s.split()) 
     return reduce(lambda s, i: s.replace(r(i), i), ignores, r(sentence)) 

>>> main('The quick brown fox jumps over the lazy dog', ['quick brown', 'lazy dog']) 
'ehT quick brown xof spmuj revo eht lazy dog' 
+0

Ich glaube nicht, dass Sie es weniger lesbar machen könnten;) –

+1

@PadraicCunningham Sie unterschätzen mich. Wie wäre es zum Beispiel, 'r' und alle seine Variablen in' _' umzubenennen? Das heißt: def _ (_): return '' .join (_ [:: - 1] für _ in _.split()) '? –

0

habe ich versucht, das Problem der überlappenden ignorieren Phrasen zum Beispiel zu lösen ['brown fox', 'quick brown'] angehoben von @PadraicCunningham.

Es gibt natürlich viel mehr Looping und Code fühlt sich weniger pythonisch an, also würde mich ein Feedback dazu interessieren, wie man das verbessert.

import re 

def _span_combiner(spans): 
    """replace overlapping spans with encompasing single span""" 
    for i, s in enumerate(spans): 
     start = s[0] 
     end = s[1] 
     for x in spans[i:]: 
      if x[0] < end: 
       end = x[1] 
     yield (start, end) 

def main(sentence, ignores): 
    # spans is a start and finish indices for each ignore phrase in order of occurence 
    spans = sorted(
      [[m.span() for m in re.finditer(p, sentence)][0] for p in ignores if p in sentence] 
    ) 
    # replace overlapping indices with single set of indices encompasing overlapped range 
    spans = [s for s in _span_combiner(spans)] 
    # recreate ignore list by slicing sentence with combined spans 
    ignores = [sentence[s[0]:s[1]] for s in spans] 
    for phrase in ignores: 
     reversed_phrase = ' '.join([word[::-1] for word in phrase.split()]) 
     sentence = sentence.replace(phrase, reversed_phrase) 

    return ' '.join(word[::-1] for word in sentence.split()) 

if __name__ == "__main__": 
    print(main('The quick brown fox jumps over the lazy dog', ['quick', 'lazy'])) 
    print(main('The quick brown fox jumps over the lazy dog', ['brown fox', 'lazy dog'])) 
    print(main('The quick brown fox jumps over the lazy dog', ['nonexistent' ,'brown fox', 'quick brown'])) 
    print(main('The quick brown fox jumps over the brown fox', ['brown fox', 'quick brown'])) 

Ergebnisse:

ehT quick nworb xof spmuj revo eht lazy god 
ehT kciuq brown fox spmuj revo eht lazy dog 
ehT quick brown fox spmuj revo eht yzal god 
ehT quick brown fox spmuj revo eht brown fox 
Verwandte Themen