Regular Expressions definierte Stelle (eine von3) ersetzen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Folgendes Problem:

ich hab einen String wie z.b. "du, bist du bist du bist du"

ich möchte aus "du" -> "ich" machen aber nur das zweite du! am besten unter angabe des index wo "du" anfängt. in diesem fall sprich String[9]

ps: re.sub("du","ich",string, count=X) funktioniert nicht, da es nur von links nach rechts zählt und man nicht auswählen kann!
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Alternative:

String "du, bist du bist du bist du"

wenn ich weiß wo das 2te du anfängt, wie kann ich das 2te du RAUSSCHNEIDEN (ähnlich wie split) und den Rest als Liste mit 2 attributen zurückgeben?

dann könnte ich nachher einen neuen string erstellen indem ich die liste anzapfe und den gewünschten String in der mitte einführe.

Bin auch offen für jede andere lösung ,)
Benutzeravatar
sparrow
User
Beiträge: 4600
Registriert: Freitag 17. April 2009, 10:28

Du kannst einen String durch das Suchwort splitten und die Teile anschließend wieder zusammenfügen, außer an der Stelle wo die Ersetzung vorgenommen werden soll.
Das geht bestimmt auch mit Regular Expressions, aber ich mag die nicht besonders.

Code: Alles auswählen

def mreplace(string, old, new, occurance):
    splits = string.split(old)
    if len(splits) < occurance:
        raise ValueError("'%s' does not occures %i times in '%s'" 
                          % (old, occurance, string))
    return new.join((old.join(splits[0:occurance]), 
                     old.join(splits[occurance:])))
    

a = "du, bist du bist du bist du"

print mreplace(a, "du", "ich", 2)
Zuletzt geändert von sparrow am Montag 10. September 2012, 18:56, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wie wäre es damit:

Code: Alles auswählen

def replace(s, word, repl):
    pos = s.index(word, 1)
    return "{}{}{}".format(s[:pos], repl, s[pos+len(word):])

replace(s, "du", "ich")
>>> 'du, bist ich bist du bist du'
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
sparrow
User
Beiträge: 4600
Registriert: Freitag 17. April 2009, 10:28

Holla die Waldfee. Eigentlich hätte ich gedacht, dass Hyperions Lösung deutlich schneller ist, da ich ja erst den ganzen String splitte und ihn hinterher wieder zusammensetze. Aber

Code: Alles auswählen

import time

def mreplace(string, old, new, occurance):
    splits = string.split(old)
    if len(splits) < occurance:
        raise ValueError("'%s' does not occures %i times in '%s'" 
                          % (old, occurance, string))
    return new.join((old.join(splits[0:occurance]), 
                     old.join(splits[occurance:])))
    

def replace(s, word, repl):
    pos = s.index(word, 1)
    return "{}{}{}".format(s[:pos], repl, s[pos+len(word):])


a = "du, bist du bist du bist du"

start1 = time.time()
print mreplace(a, "du", "ich", 2)
stop1 = time.time()

start2 = time.time()
print replace(a, "du", "ich")
stop2 = time.time()

print stop1 - start1
print stop2 - start2
Bringt:

Code: Alles auswählen

du, bist ich bist du bist du
du, bist ich bist du bist du
0.000127077102661
5.41210174561e-05
CPython 2.7.3
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also zunächst einmal misst man solche Sachen mit dem `timeit`-Modul:

Code: Alles auswählen

#!/usr/bin/env python

import time

def replace_sparrow(string, old, new, occurance=2):
    splits = string.split(old)
    if len(splits) < occurance:
        raise ValueError("'%s' does not occure %i times in '%s'"
                          % (old, occurance, string))
    return new.join((old.join(splits[0:occurance]),
                     old.join(splits[occurance:])))
   

def replace_hyperion(s, word, repl):
    pos = s.index(word, 1)
    return "{}{}{}".format(s[:pos], repl, s[pos+len(word):])



def main():
    import timeit

    a = "du, bist du bist du bist du"


    for func in [replace_sparrow, replace_hyperion]:
        t = timeit.Timer("{0}('{1}', '{2}', '{3}')".format(func.__name__, a, 
                                                           "du", "ich"),
                         "from __main__ import {0}".format(func.__name__))
        count = 10000000
        print(func.__name__, (t.timeit(count) / count))


if __name__ == "__main__":
    main()
Das ergibt auf meinem alten System:

Code: Alles auswählen

replace_sparrow 3.6277180910110475e-06
replace_hyperion 3.4617495059967042e-06
./replace.py  69,86s user 0,01s system 98% cpu 1:11,01 total
Also liege ich da knapp vor Dir. Ich benutze aber auch Python 3.2.

Ich weiß ja nicht, was Du aus Deinem Ergebnis heraus gelesen hast, aber 5.4 * 10 ^ -5 ist imho deutlich kleiner als 1.2 * 10 ^ -4 ;-) Insofern wundert mich das "aber" bei Dir...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
sparrow
User
Beiträge: 4600
Registriert: Freitag 17. April 2009, 10:28

Hyperion hat geschrieben:Ich weiß ja nicht, was Du aus Deinem Ergebnis heraus gelesen hast, aber 5.4 * 10 ^ -5 ist imho deutlich kleiner als 1.2 * 10 ^ -4 ;-) Insofern wundert mich das "aber" bei Dir...
Ah shit, die Zahl vor dem Komma hat mich so verwirrt, dass ich das Ende gar nicht mehr angeschaut habe. ;)

Gut, dann ist mein Weltbild jetzt ja wieder gerade :)
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Code: Alles auswählen

import re

def replace(string, word, repl, place):
    posl=[]
    for match in re.finditer(word, string):
          posl.append(match.start())
    pos=posl[place-1]
    return "{}{}{}".format(string[:pos], repl, string[pos+len(word):])
hab deine variante etwas umgeformt hyperion, damits allgemeingültiger ist.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nun wird es aber echt Zeit für eine List Comprehension:

Code: Alles auswählen

pos1 = [match.start() for match in re.finditer(word, string)]
oder mittels map:

Code: Alles auswählen

pos1 = map(operator.methodcaller("start"), re.finditer(word, string))
Auch solltest du mal richtige Namen in betracht ziehen. "string" (was auch noch einen eingebauten Typen verdeckt) "repl", "place" und "pos1" sind alle sehr nichtssagend.

Die start-Methode würde ich auch nicht auf jedem item aufrufen, dass reicht ja im prinzip bei ``pos1[place-1].start()``.

Und das Erstellen der Liste kann man eigentlich auch sparen:

Code: Alles auswählen

pos = next(itertools.islice(re.finditer(word, string), place-1, place)).start()
Das Leben ist wie ein Tennisball.
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Vielen Dank, werde drüber nachdenken.

Nehmen wir an ich habe folgenden String

'[H]C(=O)CCC1=C(CC)C=C(CCCC)C(CC(=O)OC)=C1C'

es handelt sich um ein molekül im .smiles format.

Ich muss wissen wie weit die carbonylgruppen voneinander entfernt sind: C(=O)

Das Problem ist immer wenn klammern kommen wie zb, C1=C(CC)C hier, dann darf (CC) nicht mitgezählt werden, da es sich um eine verzweigung handelt und nicht zum direkten weg der carbonylgruppen beiträgt.

Allerdings taucht die zweite carbonylgruppe (eher carboxy, aber das sei jetzt mal egal) innerhalb von klammern auf, das macht aber nichts, da der weg ja trotzdem vorhanden ist. Im grunde lässt sich die smiles zeile in folgendes umschreiben:
'[H]C(=O)CCC1=C(CC)C=C(CCCC)C(=C1C)CC(=O)OC'
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Und das ist der Grund, warum man in seine Problembeschreibung immer das "große Problem" hineinschreibt. Da beliebig tiefe Verschachtelungen möglich sind, kannst du das nicht mehr mit regulären Ausdrücken lösen, dafür brauchst du einen, wenn auch sehr trivialen, Parser. Noch einfacher ist das Problem aber, wenn du einfach mal nach "python smiles" suchst, es existieren dazu nämlich schon fertige Bibliotheken.
Das Leben ist wie ein Tennisball.
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

cool danke, so kann man zeit sparen ;P
dafür hab ich etwas gelernt^^

schreibt man parser nicht mit regulären ausdrücken?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

flummi hat geschrieben:schreibt man parser nicht mit regulären ausdrücken?
Nur um die Tokens zu extrahieren. Nur mit regulären Ausdrücken sind beliebige Verschachtelungstiefen mathematisch nicht möglich.
Das Leben ist wie ein Tennisball.
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Code: Alles auswählen

sekura@sekura-GA-MA770-UD3:~/frowns$ python setup.py build
running build
running build_py
running build
running build_ext
my_init_posix: changing gcc to g++
building '_pysssr' extension
g++ -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c pysssr.cxx -o build/temp.linux-i686-2.7/pysssr.o
cc1plus: Warnung: Kommandozeilenoption »-Wstrict-prototypes« ist gültig für Ada/C/ObjC, aber nicht für C++ [standardmäßig aktiviert]
pysssr.cxx:5:20: schwerwiegender Fehler: Python.h: Datei oder Verzeichnis nicht gefunden
Kompilierung beendet.
error: command 'g++' failed with exit status 1
Readme: pysssr requires a C++ compiler and is known to compile and work
under windows and linux/macosx using gcc 3.0 or higher.

sudo apt-get install gcc -->> gcc ist schon die aktuellste version

was muss ich machen? bzw. was funktioniert hier nicht?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Warum schaust du in die Readme, wenn die Fehlermeldung dort ganz eindeutig steht?
pysssr.cxx:5:20: schwerwiegender Fehler: Python.h: Datei oder Verzeichnis nicht gefunden
Wahrscheinlich fehlt bei dir einfach nur das python-dev Paket oder der dazugehörige Include-Pfad. Hast du mal geschaut, ob du das Projekt (welches auch immer) wirklich selber kompilieren musst und ob es nicht vielleicht schon im Paketmanager steckt?
Das Leben ist wie ein Tennisball.
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Also in der readme stand ich soll das so eingeben ;P

wie schau ich denn nach "ob es schon im packetmanager steckt". ja das ist bestimmt ne doofe frage aber ich hab linux seit 2 wochen drauf, und hab einiges aufzuholen ...
was passiert denn genau beim compilen?
da wird aus textdateien eine binary geschrieben oder nicht? Unter windows dann text -> .exe.

unter linux wird aus textdatei eine shell geschrieben die auch eine textdatei ist?!

also falls du sowas wie das ubuntu software center meinst, da liefert "frowns" keinen treffer.
Antworten