2012-04-08 14 views
4

Angenommen, ich habe 10 verschiedene Token, "(TOKEN)" in einer Zeichenfolge. Wie ersetze ich 2 dieser zufälligen Token durch eine andere Zeichenfolge und lasse die anderen Token intakt?Python: Wie N zufällige Zeichenfolge Vorkommen im Text ersetzen?

+1

Wollen Sie damit sagen, dass Sie 10 Instanzen von die gleiche Zeichenfolge (zB "foo") in der Zeichenfolge? Oder dass Sie 10 einzelne eindeutige Saiten in der Saite haben? – Garen

Antwort

1

Wenn Sie genau zwei benötigen, dann:

  1. die Token Detect (halten einige Links zu ihnen, wie Index in den String)
  2. zwei Wählen Sie zufällig (random.choice)
  3. Ersetzen Sie sie
+1

Vielleicht könntest du den 3. Schritt noch ein wenig mehr für das OP erweitern? Ich vermute, sie könnten genauso interessiert sein, wie man diese Indizes spezifisch ersetzt. Ich fühle den 3. Schritt ist zu stark vereinfacht? – jdi

1

Was versuchst du genau zu tun? Eine gute Antwort wird sich verlassen ...

Das heißt, eine Brute-Force-Lösung, die den Sinn kommt, ist:

  1. Speichern Sie die 10-Token in einem Array, so dass Tokens [0] das erste Token, Token [1] ist die zweite, ... und so weiter
  2. ein Wörterbuch erstellen jeden eindeutigen „(TOKEN)“ mit zwei Zahlen zu assoziieren: start_idx, end_idx
  3. einen kleinen Parser schreiben, die durch Wanderungen Ihre Zeichenfolge und sucht nach jedem der 10 Token. Wenn eine solche gefunden wird, notieren Sie die Start-/Endindizes (als start_idx, end_idx) in der Zeichenfolge, in der das Token auftritt.
  4. Wenn Sie das Parsing durchgeführt haben, generieren Sie eine Zufallszahl im Bereich [0,9]. Nennen wir diese R
  5. nun Ihre random "(TOKEN)" ist Tokens [R];
  6. Verwenden Sie das Wörterbuch in Schritt (3), um die Werte start_idx, end_idx in der Zeichenfolge zu finden; ersetzen Sie den Text dort mit "einem anderen String"
+1

Ich denke, Sie haben die Absichten des OP falsch interpretiert. Er sagt, dass er eine Zeichenfolge hat, die, sagen wir mal, 10 Vorkommen von "TOKEN" hat und er nur 2 von ihnen zufällig ersetzen will. Worüber du sprichst, ist, dass ich 10 verschiedene Tokens habe, die ich denke, und echte Token zurückgebe. – jdi

+0

Gah, bitte lies es noch einmal. Ich habe versehentlich zu früh eingereicht. – Garen

+0

Ähm, ja, vielleicht hast du recht - dass er 10 Instanzen der gleichen Zeichenfolge hat. Nicht, dass jeder Token einzigartig ist. – Garen

1

Meine Lösung in Code:

import random 

s = "(TOKEN)test(TOKEN)fgsfds(TOKEN)qwerty(TOKEN)42(TOKEN)(TOKEN)ttt" 
replace_from = "(TOKEN)" 
replace_to = "[REPLACED]" 
amount_to_replace = 2 

def random_replace(s, replace_from, replace_to, amount_to_replace): 
    parts = s.split(replace_from) 
    indices = random.sample(xrange(len(parts) - 1), amount_to_replace) 

    replaced_s_parts = list() 

    for i in xrange(len(parts)): 
     replaced_s_parts.append(parts[i]) 
     if i < len(parts) - 1: 
      if i in indices: 
       replaced_s_parts.append(replace_to) 
      else: 
       replaced_s_parts.append(replace_from) 

    return "".join(replaced_s_parts) 

#TEST 

for i in xrange(5): 
    print random_replace(s, replace_from, replace_to, 2) 

Erläuterung:

  1. Splits Zeichenfolge in mehrere Teile mit replace_from
  2. Indizes von Token wählt ersetzen mit random.sample. Diese zurückgegebene Liste enthält eindeutige Nummern.
  3. Erstellen Sie eine Liste für die String-Rekonstruktion, wobei Sie Token mit generiertem Index durch replace_to ersetzen.
  4. Concatenate alle Listenelemente in einzelne Zeichenfolge
1

diese Lösung Versuchen:

import random 

def replace_random(tokens, eqv, n): 
    random_tokens = eqv.keys() 
    random.shuffle(random_tokens) 
    for i in xrange(n): 
     t = random_tokens[i] 
     tokens = tokens.replace(t, eqv[t]) 
    return tokens 

Unter der Annahme, dass ein String mit Token vorhanden ist, und eine geeignete Äquivalenztabelle für jeden Token mit einem Ersatz aufgebaut werden kann:

tokens = '(TOKEN1) (TOKEN2) (TOKEN3) (TOKEN4) (TOKEN5) (TOKEN6) (TOKEN7) (TOKEN8) (TOKEN9) (TOKEN10)' 

equivalences = { 
    '(TOKEN1)' : 'REPLACEMENT1', 
    '(TOKEN2)' : 'REPLACEMENT2', 
    '(TOKEN3)' : 'REPLACEMENT3', 
    '(TOKEN4)' : 'REPLACEMENT4', 
    '(TOKEN5)' : 'REPLACEMENT5', 
    '(TOKEN6)' : 'REPLACEMENT6', 
    '(TOKEN7)' : 'REPLACEMENT7', 
    '(TOKEN8)' : 'REPLACEMENT8', 
    '(TOKEN9)' : 'REPLACEMENT9', 
    '(TOKEN10)' : 'REPLACEMENT10' 
} 

Sie können es so nennen:

replace_random(tokens, equivalences, 2) 
> '(TOKEN1) REPLACEMENT2 (TOKEN3) (TOKEN4) (TOKEN5) (TOKEN6) (TOKEN7) (TOKEN8) REPLACEMENT9 (TOKEN10)' 
+0

Dies ist ähnlich wie die andere Antwort, die ich denke, nahm den missverstandenen Ansatz des Ersetzens verschiedener Token.Ich glaube wirklich, dass das OP bedeutet, dass er 10 "Token" -Ereignisse in einer großen Folge sagt und er will nur zufällig zwei durch etwas anderes ersetzen. Nicht zufällig Ersetzungen auf verschiedenen Mustern auswählen – jdi

1

Es gibt viele Möglichkeiten, dies zu tun. Mein Ansatz wäre, eine Funktion zu schreiben, die die ursprüngliche Zeichenfolge, den Token-String nimmt, und eine Funktion, die den Ersatztext für das Auftreten des Tokens im Original zurück:

def strByReplacingTokensUsingFunction(original, token, function): 
    outputComponents = [] 
    matchNumber = 0 
    unexaminedOffset = 0 
    while True: 
     matchOffset = original.find(token, unexaminedOffset) 
     if matchOffset < 0: 
      matchOffset = len(original) 
     outputComponents.append(original[unexaminedOffset:matchOffset]) 
     if matchOffset == len(original): 
      break 
     unexaminedOffset = matchOffset + len(token) 
     replacement = function(original=original, offset=matchOffset, matchNumber=matchNumber, token=token) 
     outputComponents.append(replacement) 
     matchNumber += 1 
    return ''.join(outputComponents) 

(Sie sicherlich die ändern könnten Verwenden Sie kürzere Bezeichner. Mein Stil ist etwas ausführlicher als der typische Python-Stil.)

Mit dieser Funktion ist es leicht, zwei zufällige Vorkommen von zehn zu ersetzen. Hier einige Beispiel-Eingang:

sampleInput = 'a(TOKEN)b(TOKEN)c(TOKEN)d(TOKEN)e(TOKEN)f(TOKEN)g(TOKEN)h(TOKEN)i(TOKEN)j(TOKEN)k' 

Das statistische Modul eine praktische Methode für die Kommissionierung zufällige Elemente aus einer Population hat (nicht das gleiche Element Kommissionierung zweimal):

import random 
replacementIndexes = random.sample(range(10), 2) 

Dann können wir die Funktion oben die zufällig gewählten Vorkommen ersetzen:

sampleOutput = strByReplacingTokensUsingFunction(sampleInput, '(TOKEN)', 
    (lambda matchNumber, token, **keywords: 
     'REPLACEMENT' if (matchNumber in replacementIndexes) else token)) 
print sampleOutput 

Und hier einige Testausgang:

Hier ist ein weiterer Lauf:

a(TOKEN)bREPLACEMENTc(TOKEN)d(TOKEN)e(TOKEN)f(TOKEN)gREPLACEMENTh(TOKEN)i(TOKEN)j(TOKEN)k 
2
>>> import random 
>>> text = '(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)' 
>>> token = '(TOKEN)' 
>>> replace = 'foo' 
>>> num_replacements = 2 
>>> num_tokens = text.count(token) #10 in this case 
>>> points = [0] + sorted(random.sample(range(1,num_tokens+1),num_replacements)) + [num_tokens+1] 
>>> replace.join(token.join(text.split(token)[i:j]) for i,j in zip(points,points[1:])) 
'(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__foo__(TOKEN)__foo__(TOKEN)__(TOKEN)__(TOKEN)' 

In Funktion Form:

>>> def random_replace(text, token, replace, num_replacements): 
     num_tokens = text.count(token) 
     points = [0] + sorted(random.sample(range(1,num_tokens+1),num_replacements)) + [num_tokens+1] 
     return replace.join(token.join(text.split(token)[i:j]) for i,j in zip(points,points[1:])) 

>>> random_replace('....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....','(TOKEN)','FOO',2) 
'....FOO....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....FOO....' 

Test:

>>> for i in range(0,9): 
     print random_replace('....(0)....(0)....(0)....(0)....(0)....(0)....(0)....(0)....','(0)','(%d)'%i,i) 


....(0)....(0)....(0)....(0)....(0)....(0)....(0)....(0).... 
....(0)....(0)....(0)....(0)....(1)....(0)....(0)....(0).... 
....(0)....(0)....(0)....(0)....(0)....(2)....(2)....(0).... 
....(3)....(0)....(0)....(3)....(0)....(3)....(0)....(0).... 
....(4)....(4)....(0)....(0)....(4)....(4)....(0)....(0).... 
....(0)....(5)....(5)....(5)....(5)....(0)....(0)....(5).... 
....(6)....(6)....(6)....(0)....(6)....(0)....(6)....(6).... 
....(7)....(7)....(7)....(7)....(7)....(7)....(0)....(7).... 
....(8)....(8)....(8)....(8)....(8)....(8)....(8)....(8).... 
0
from random import sample 

mystr = 'adad(TOKEN)hgfh(TOKEN)hjgjh(TOKEN)kjhk(TOKEN)jkhjk(TOKEN)utuy(TOKEN)tyuu(TOKEN)tyuy(TOKEN)tyuy(TOKEN)tyuy(TOKEN)' 

def replace(mystr, substr, n_repl, replacement='XXXXXXX', tokens=10, index=0): 
    choices = sorted(sample(xrange(tokens),n_repl)) 
    for i in xrange(choices[-1]+1): 
     index = mystr.index(substr, index) + 1 
     if i in choices: 
      mystr = mystr[:index-1] + mystr[index-1:].replace(substr,replacement,1) 
    return mystr 

print replace(mystr,'(TOKEN)',2) 
+1

Es ist wahrscheinlich besser, 'range' anstelle von' xrange' für Python 3-Kompatibilität zu verwenden. – jamylak

Verwandte Themen