2014-02-27 8 views
5

Gibt es eine Möglichkeit, doppelte und kontinuierliche Wörter/Sätze in einer Zeichenfolge zu entfernen? Z.B.Gibt es eine Möglichkeit, doppelte und kontinuierliche Wörter/Phrasen in einer Zeichenfolge zu entfernen?

[in]:foo foo bar bar foo bar

[out]:foo bar foo bar

Ich habe versucht, dies:

>>> s = 'this is a foo bar bar black sheep , have you any any wool woo , yes sir yes sir three bag woo wu wool' 
>>> [i for i,j in zip(s.split(),s.split()[1:]) if i!=j] 
['this', 'is', 'a', 'foo', 'bar', 'black', 'sheep', ',', 'have', 'you', 'any', 'wool', 'woo', ',', 'yes', 'sir', 'yes', 'sir', 'three', 'bag', 'woo', 'wu'] 
>>> " ".join([i for i,j in zip(s.split(),s.split()[1:]) if i!=j]+[s.split()[-1]]) 
'this is a foo bar black sheep , have you any wool woo , yes sir yes sir three bag woo wu' 

Was passiert, wenn es ein wenig komplizierter wird, und ich will Phrasen entfernen (sagen wir, Phrasen können aus bis zu 5 Wörtern bestehen)? Wie kann es gemacht werden? Z.B.

[in]:foo bar foo bar foo bar

[out]:foo bar

Ein weiteres Beispiel:

[in]:this is a sentence sentence sentence this is a sentence where phrases phrases duplicate where phrases duplicate . sentence are not prhases .

[out]:this is a sentence where phrases duplicate . sentence are not prhases .

Antwort

13

Sie können re-Modul dafür verwenden.

>>> s = 'foo foo bar bar' 
>>> re.sub(r'\b(.+)\s+\1\b', r'\1', s) 
'foo bar' 

>>> s = 'foo bar foo bar foo bar' 
>>> re.sub(r'\b(.+)\s+\1\b', r'\1', s) 
'foo bar foo bar' 

Wenn Sie eine beliebige Anzahl von aufeinanderfolgenden Auftritten übereinstimmen soll:

>>> s = 'foo bar foo bar foo bar' 
>>> re.sub(r'\b(.+)(\s+\1\b)+', r'\1', s) 
'foo bar'  

bearbeiten. Ein Zusatz für dein letztes Beispiel. Um dies zu tun, müssen Sie re rufen, während es doppelte Phrasen gibt. Also:

>>> s = 'this is a sentence sentence sentence this is a sentence where phrases phrases duplicate where phrases duplicate' 
>>> while re.search(r'\b(.+)(\s+\1\b)+', s): 
... s = re.sub(r'\b(.+)(\s+\1\b)+', r'\1', s) 
... 
>>> s 
'this is a sentence where phrases duplicate' 
+1

Clever Antwort! +1 Aber würde dies zu Leistungsproblemen führen, wenn es auf eine sehr große Zeichenfolge angewendet wird? – ridgerunner

-1
txt1 = 'this is a foo bar bar black sheep , have you any any wool woo , yes sir yes sir three bag woo wu wool' 
txt2 = 'this is a sentence sentence sentence this is a sentence where phrases phrases duplicate where phrases duplicate' 

def remove_duplicates(txt): 
    result = [] 
    for word in txt.split(): 
     if word not in result: 
      result.append(word) 
    return ' '.join(result) 

Ouput:

In [7]: remove_duplicate_words(txt1)                                 
Out[7]: 'this is a foo bar black sheep , have you any wool woo yes sir three bag wu'                     

In [8]: remove_duplicate_words(txt2)                                 
Out[8]: 'this is a sentence where phrases duplicate' 
-1

Dies sollte eine beliebige Anzahl benachbarter Duplikate beheben, und arbeitet mit Ihren Beispielen. Ich konvertieren den String in eine Liste, es zu beheben, dann für die Ausgabe in einen String konvertieren zurück:

mywords = "foo foo bar bar foo bar" 
list = mywords.split() 
def remove_adjacent_dups(alist): 
    result = [] 
    most_recent_elem = None 
    for e in alist: 
     if e != most_recent_elem: 
      result.append(e) 
      most_recent_elem = e 
    to_string = ' '.join(result) 
    return to_string 

print remove_adjacent_dups(list) 

Ausgang:

foo bar foo bar 
6

Ich liebe itertools. Es scheint, als ob ich jedes Mal, wenn ich etwas schreiben möchte, es bereits habe. In diesem Fall nimmt groupby eine Liste und gruppiert wiederholte sequenzielle Elemente aus dieser Liste in ein Tupel von (item_value, iterator_of_those_values).Verwenden Sie es hier mögen:

>>> s = 'this is a foo bar bar black sheep , have you any any wool woo , yes sir yes sir three bag woo wu wool' 
>>> ' '.join(item[0] for item in groupby(s.split())) 
'this is a foo bar black sheep , have you any wool woo , yes sir yes sir three bag woo wu wool' 

Lassen Sie uns so verlängern, dass ein wenig mit einer Funktion, die eine Liste mit duplizierten wiederholt Werte zurückgibt entfernt:

from itertools import chain, groupby 

def dedupe(lst): 
    return list(chain(*[item[0] for item in groupby(lst)])) 

Das ist für Ein-Wort-Sätze ist toll, aber nicht hilfreich für längere Sätze. Was ist zu tun? Nun, zuerst werden wir nach längeren Sätzen suchen, indem wir über unseren ursprünglichen Satz schreiten:

Jetzt kochen wir! OK. Unsere Strategie besteht also darin, zunächst alle Einzelwortduplikate zu entfernen. Als nächstes entfernen wir die Zweiwort-Duplikate, beginnend mit Offset 0 und 1. Danach beginnen Dreiwortduplikate mit den Offsets 0, 1 und 2 und so weiter, bis wir Fünf-Wort-Duplikate gefunden haben:

def cleanse(list_of_words, max_phrase_length): 
    for length in range(1, max_phrase_length + 1): 
     for offset in range(length): 
      list_of_words = dedupe(stride(list_of_words, offset, length)) 

    return list_of_words 

Dass sie alle zusammen:

from itertools import chain, groupby 

def stride(lst, offset, length): 
    if offset: 
     yield lst[:offset] 

    while True: 
     yield lst[offset:offset + length] 
     offset += length 
     if offset >= len(lst): 
      return 

def dedupe(lst): 
    return list(chain(*[item[0] for item in groupby(lst)])) 

def cleanse(list_of_words, max_phrase_length): 
    for length in range(1, max_phrase_length + 1): 
     for offset in range(length): 
      list_of_words = dedupe(stride(list_of_words, offset, length)) 

    return list_of_words 

a = 'this is a sentence sentence sentence this is a sentence where phrases phrases duplicate where phrases duplicate . sentence are not prhases .' 

b = 'this is a sentence where phrases duplicate . sentence are not prhases .' 

print ' '.join(cleanse(a.split(), 5)) == b 
+0

wortreich noch itertooly =) – alvas

+0

Heh! Ich bin mir sicher, dass das verkürzt werden könnte, und Teile davon wären einzeilig, aber ich wollte ein Gleichgewicht zwischen Knappheit und Lesbarkeit herstellen. Ich hoffe, ich habe es getroffen. :-) –

0

ich persönlich glaube nicht, dass wir keine anderen Module hierfür verwenden müssen (obwohl ich einige von ihnen zugeben sind gut). Ich schaffte das einfach mit einer einfachen Schleife, indem ich zuerst die Zeichenfolge in eine Liste umwandelte. Ich habe es bei allen oben aufgeführten Beispielen versucht. Es funktioniert gut.

sentence = str(raw_input("Please enter your sentence:\n")) 

word_list = sentence.split() 

def check_if_same(i,j): # checks if two sets of lists are the same 

    global word_list 
    next = (2*j)-i # this gets the end point for the second of the two lists to compare (it is essentially j + phrase_len) 
    is_same = False 
    if word_list[i:j] == word_list[j:next]: 

     is_same = True 
     # The line below is just for debugging. Prints lists we are comparing and whether it thinks they are equal or not 
     #print "Comparing: " + ' '.join(word_list[i:j]) + " " + ''.join(word_list[j:next]) + " " + str(answer) 

    return is_same 

phrase_len = 1 

while phrase_len <= int(len(word_list)/2): # checks the sentence for different phrase lengths 

    curr_word_index=0 

    while curr_word_index < len(word_list): # checks all the words of the sentence for the specified phrase length 

     result = check_if_same(curr_word_index, curr_word_index + phrase_len) # checks similarity 

     if result == True: 
      del(word_list[curr_word_index : curr_word_index + phrase_len]) # deletes the repeated phrase 
     else: 
      curr_word_index += 1 

    phrase_len += 1 

print "Answer: " + ' '.join(word_list) 
0

Mit einem Muster ähnlich sharcashmo das Muster, können Sie subn, die die Anzahl der Ersetzungen zurück, innerhalb einer while-Schleife verwenden:

import re 

txt = r'this is a sentence sentence sentence this is a sentence where phrases phrases duplicate where phrases duplicate . sentence are not phrases .' 

pattern = re.compile(r'(\b\w+(?: \w+)*)(?: \1)+\b') 
repl = r'\1' 

res = txt 

while True: 
    [res, nbr] = pattern.subn(repl, res) 
    if (nbr == 0): 
     break 

print res 

, wenn es nicht mehr Ersetzungen die while Schleife stoppt.

Mit dieser Methode können Sie alle überlappenden Übereinstimmungen erhalten (das ist bei einem einzelnen Durchgang in einem Ersetzungskontext unmöglich), ohne zweimal das gleiche Muster zu testen.

Verwandte Themen